Użycie jquery do uzyskania pozycji elementu względem rzutni

117

Jaki jest właściwy sposób na uzyskanie pozycji elementu na stronie względem widoku (a nie dokumentu). jQuery.offsetfunkcja wydawała się obiecująca:

Uzyskaj aktualne współrzędne pierwszego elementu lub ustaw współrzędne każdego elementu w zestawie dopasowanych elementów względem dokumentu.

Ale to odnosi się do dokumentu. Czy istnieje równoważna metoda, która zwraca przesunięcia względem rzutni?

DA.
źródło
5
UWAGA: Zobacz odpowiedź @Igor G ...
Carl Smith
3
Dla DA naprawdę powinieneś ustawić odpowiedź Igora G jako akceptowaną, to ratuje życie!
Vincent Duprez

Odpowiedzi:

26

Zajrzyj do wtyczki Dimensions, w szczególności scrollTop()/ scrollLeft(). Informacje można znaleźć pod adresem http://api.jquery.com/scrollTop .

Agent_9191
źródło
8
Nie chciałem używać innej wtyczki, ale $ (window) .scrollTop () jest dokładnie tym, czego potrzebowałem! Dzięki!
DA.
16
Wtyczka wymiarów jest teraz częścią rdzenia jQuery. Wtyczka ViewPort może być również przydatna: appelsiini.net/projects/viewport
StriplingWarrior
287

Najłatwiejszym sposobem określenia rozmiaru i położenia elementu jest wywołanie jego metody getBoundingClientRect () . Ta metoda zwraca pozycje elementów we współrzędnych rzutni. Nie oczekuje żadnych argumentów i zwraca obiekt z właściwościami left, right, top i bottom . Właściwości left i top określają współrzędne X i Y lewego górnego rogu elementu, a właściwości prawy i dolny określają współrzędne prawego dolnego rogu.

element.getBoundingClientRect(); // Get position in viewport coordinates

Obsługiwane wszędzie.

Igor G.
źródło
15
To niesamowite, że ta metoda została dodana przez IE5 ... kiedy coś jest dobre, to jest dobre!
roy riojas
Na początku wydawało się to świetne, ale nie uwzględnia sytuacji, w których użytkownik korzysta z przeglądarki Mobile Safari 7.
MyNameIsKo
2
Nieobsługiwane przez najnowszy firefoxgetBoundingClientRect is not a function
user007
2
@ user007 Potwierdzam, że jest obsługiwany przez najnowszego firefoxa.
adriendenat
26
Świetna odpowiedź, a żeby to było jquery, po prostu zrób to w ten sposób: $('#myElement')[0].getBoundingClientRect().top(lub jakakolwiek inna pozycja)
Guillaume Arluison
40

Oto dwie funkcje do uzyskania wysokości strony i ilości przewijania (x, y) bez użycia wtyczki wymiarów (nadęty):

// getPageScroll() by quirksmode.com
function getPageScroll() {
    var xScroll, yScroll;
    if (self.pageYOffset) {
      yScroll = self.pageYOffset;
      xScroll = self.pageXOffset;
    } else if (document.documentElement && document.documentElement.scrollTop) {
      yScroll = document.documentElement.scrollTop;
      xScroll = document.documentElement.scrollLeft;
    } else if (document.body) {// all other Explorers
      yScroll = document.body.scrollTop;
      xScroll = document.body.scrollLeft;
    }
    return new Array(xScroll,yScroll)
}

// Adapted from getPageSize() by quirksmode.com
function getPageHeight() {
    var windowHeight
    if (self.innerHeight) { // all except Explorer
      windowHeight = self.innerHeight;
    } else if (document.documentElement && document.documentElement.clientHeight) {
      windowHeight = document.documentElement.clientHeight;
    } else if (document.body) { // other Explorers
      windowHeight = document.body.clientHeight;
    }
    return windowHeight
}
Corey Ballou
źródło
To jest genialne. Bardzo przydatne.
Jimmy
Z ciekawości, dlaczego w tym przypadku użyłeś właściwości „self” zamiast window?
dkugappi
23

jQuery.offsetmusi być połączone z scrollTopi scrollLeftjak pokazano na tym schemacie:

przewijanie rzutni i odsunięcie elementu

Próbny:

function getViewportOffset($e) {
  var $window = $(window),
    scrollLeft = $window.scrollLeft(),
    scrollTop = $window.scrollTop(),
    offset = $e.offset(),
    rect1 = { x1: scrollLeft, y1: scrollTop, x2: scrollLeft + $window.width(), y2: scrollTop + $window.height() },
    rect2 = { x1: offset.left, y1: offset.top, x2: offset.left + $e.width(), y2: offset.top + $e.height() };
  return {
    left: offset.left - scrollLeft,
    top: offset.top - scrollTop,
    insideViewport: rect1.x1 < rect2.x2 && rect1.x2 > rect2.x1 && rect1.y1 < rect2.y2 && rect1.y2 > rect2.y1
  };
}
$(window).on("load scroll resize", function() {
  var viewportOffset = getViewportOffset($("#element"));
  $("#log").text("left: " + viewportOffset.left + ", top: " + viewportOffset.top + ", insideViewport: " + viewportOffset.insideViewport);
});
body { margin: 0; padding: 0; width: 1600px; height: 2048px; background-color: #CCCCCC; }
#element { width: 384px; height: 384px; margin-top: 1088px; margin-left: 768px; background-color: #99CCFF; }
#log { position: fixed; left: 0; top: 0; font: medium monospace; background-color: #EEE8AA; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

<!-- scroll right and bottom to locate the blue square -->
<div id="element"></div>
<div id="log"></div>

Salman A
źródło
2
to działało świetnie dla mnie, ale używałem
Jordan
W każdym razie jest to absolutnie poprawna odpowiedź. Wszystkie inne mają problemy w zależności od konfiguracji myszy / przewijania delta, przeglądarek, lokalizacji obiektu itp.
Pedro Ferreira
2

Oto funkcja, która oblicza bieżące położenie elementu w rzutni:

/**
 * Calculates the position of a given element within the viewport
 *
 * @param {string} obj jQuery object of the dom element to be monitored
 * @return {array} An array containing both X and Y positions as a number
 * ranging from 0 (under/right of viewport) to 1 (above/left of viewport)
 */
function visibility(obj) {
    var winw = jQuery(window).width(), winh = jQuery(window).height(),
        elw = obj.width(), elh = obj.height(),
        o = obj[0].getBoundingClientRect(),
        x1 = o.left - winw, x2 = o.left + elw,
        y1 = o.top - winh, y2 = o.top + elh;

    return [
        Math.max(0, Math.min((0 - x1) / (x2 - x1), 1)),
        Math.max(0, Math.min((0 - y1) / (y2 - y1), 1))
    ];
}

Zwracane wartości są obliczane w następujący sposób:

Stosowanie:

visibility($('#example'));  // returns [0.3742887830933581, 0.6103752759381899]

Próbny:

function visibility(obj) {var winw = jQuery(window).width(),winh = jQuery(window).height(),elw = obj.width(),
    elh = obj.height(), o = obj[0].getBoundingClientRect(),x1 = o.left - winw, x2 = o.left + elw, y1 = o.top - winh, y2 = o.top + elh; return [Math.max(0, Math.min((0 - x1) / (x2 - x1), 1)),Math.max(0, Math.min((0 - y1) / (y2 - y1), 1))];
}
setInterval(function() {
  res = visibility($('#block'));
  $('#x').text(Math.round(res[0] * 100) + '%');
  $('#y').text(Math.round(res[1] * 100) + '%');
}, 100);
#block { width: 100px; height: 100px; border: 1px solid red; background: yellow; top: 50%; left: 50%; position: relative;
} #container { background: #EFF0F1; height: 950px; width: 1800px; margin-top: -40%; margin-left: -40%; overflow: scroll; position: relative;
} #res { position: fixed; top: 0; z-index: 2; font-family: Verdana; background: #c0c0c0; line-height: .1em; padding: 0 .5em; font-size: 12px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="res">
  <p>X: <span id="x"></span></p>
  <p>Y: <span id="y"></span></p>
</div>
<div id="container"><div id="block"></div></div>

Arne
źródło
0

Okazało się, że odpowiedź od cballou nie działa już w Firefoksie od stycznia 2014 r. W szczególności if (self.pageYOffset)nie uruchamia się, jeśli klient przewija się w prawo, ale nie w dół - ponieważ 0jest to błędna liczba. Przez jakiś czas pozostawało to niewykryte, ponieważ Firefox obsługiwał document.body.scrollLeft/ Top, ale to już nie działa (w przeglądarce Firefox 26.0).

Oto moje zmodyfikowane rozwiązanie:

var getPageScroll = function(document_el, window_el) {
  var xScroll = 0, yScroll = 0;
  if (window_el.pageYOffset !== undefined) {
    yScroll = window_el.pageYOffset;
    xScroll = window_el.pageXOffset;
  } else if (document_el.documentElement !== undefined && document_el.documentElement.scrollTop) {
    yScroll = document_el.documentElement.scrollTop;
    xScroll = document_el.documentElement.scrollLeft;
  } else if (document_el.body !== undefined) {// all other Explorers
    yScroll = document_el.body.scrollTop;
    xScroll = document_el.body.scrollLeft;
  }
  return [xScroll,yScroll];
};

Przetestowane i działające w FF26, Chrome 31, IE11. Prawie na pewno działa na starszych wersjach wszystkich z nich.

pglhall
źródło