Znajdowanie pozycji elementu względem dokumentu

113

Jaki jest najłatwiejszy sposób określenia pozycji elementów względem dokumentu / treści / okna przeglądarki?

W tej chwili używam .offsetLeft/offsetTop, ale ta metoda podaje tylko pozycję względem elementu nadrzędnego, więc musisz określić, ilu rodziców ma element ciała, aby poznać położenie względem pozycji ciała / okna przeglądarki / dokumentu.

Ta metoda jest również uciążliwa.

einstein
źródło

Odpowiedzi:

59

Możesz przejść offsetParentdo najwyższego poziomu DOM.

function getOffsetLeft( elem )
{
    var offsetLeft = 0;
    do {
      if ( !isNaN( elem.offsetLeft ) )
      {
          offsetLeft += elem.offsetLeft;
      }
    } while( elem = elem.offsetParent );
    return offsetLeft;
}
KeatsKelleher
źródło
28
Nie, nie ma, gdy którykolwiek element nadrzędny (szczególnie element html !!!) ma marginesy, dopełnienia lub obramowania.
Flash Thunder
jeśli chodzi o rzeczy związane z marginesami ... może pomóc ustawienie rozmiaru pudełka na border-box ... lub coś podobnego ... nic, czego nie można naprawić ...
Najpierw musisz zdecydować, czy wziąć pod uwagę granicę i margines zgodnie z wielkością pudełka. Po drugie, należy wziąć pod uwagę zwinięty margines. I wreszcie w przyszłości sytuacja będzie bardziej skomplikowana, co pogorszy tę odpowiedź.
xianshenglu
6
Dlaczego jest to akceptowana odpowiedź? Jest to przestarzałe i słabo działające. Zrób sobie przysługę i użyj metody getBoundingClientRect (), jak sugerowano w innych odpowiedziach.
Fabian von Ellerts
177

Możesz dostać się na górę i w lewo bez przechodzenia przez DOM w ten sposób:

function getCoords(elem) { // crossbrowser version
    var box = elem.getBoundingClientRect();

    var body = document.body;
    var docEl = document.documentElement;

    var scrollTop = window.pageYOffset || docEl.scrollTop || body.scrollTop;
    var scrollLeft = window.pageXOffset || docEl.scrollLeft || body.scrollLeft;

    var clientTop = docEl.clientTop || body.clientTop || 0;
    var clientLeft = docEl.clientLeft || body.clientLeft || 0;

    var top  = box.top +  scrollTop - clientTop;
    var left = box.left + scrollLeft - clientLeft;

    return { top: Math.round(top), left: Math.round(left) };
}
bazylia
źródło
6
Ta odpowiedź nie uwzględnia przesunięć rodziców. To tylko w odniesieniu do widoku
Nickey
3
@Nickey, to nieprawda - pozycja rzutni plus sprawdzanie przesunięcia przewijania daje współrzędne w odniesieniu do całego dokumentu.
natchiketa
1
Może powodować błędy na urządzeniach mobilnych stackoverflow.com/a/32623832/962634 Potrzeba badań
bazylia
1
Dlaczego odejmujesz clientTop / clientLeft?
Teemoh
1
@Teemoh clientTop / clientLeft odpowiada wartościom granicznym <html>elementu.
Raphael Rafatpanah
98

Możesz użyć element.getBoundingClientRect()do pobrania pozycji elementu względem rzutni.

Następnie użyj document.documentElement.scrollTopdo obliczenia odsunięcia rzutni.

Suma tych dwóch da pozycję elementu względem dokumentu:

element.getBoundingClientRect().top + document.documentElement.scrollTop
dy_
źródło
10
Względem rzutni nie jest to samo, co względem dokumentu. Jeśli strona zostanie nieco przewinięta w dół, wówczas górna część względem widoku będzie mniejsza niż górna część względem dokumentu.
MrVimes
14
zaczyna względem rzutni i dodaje scrollY, aby uzyskać odniesienie do dokumentu.
Joaquin Cuenca Abela
2
document.documentElement.scrollTopnie działa w Safari, użyj window.scrollYzamiast tego
Fabian von Ellerts
7

Sugeruję użycie

element.getBoundingClientRect()

jak zaproponowano tutaj zamiast ręcznego obliczania przesunięcia za pomocą offsetLeft , offsetTop i offsetParent . zgodnie z propozycją w tym miejscu W pewnych okolicznościach * ręczne przechodzenie daje nieprawidłowe wyniki. Zobacz ten Plunker: http://plnkr.co/pC8Kgj

* Gdy element znajduje się wewnątrz przewijalnego elementu nadrzędnego z pozycją statyczną (= domyślną).

HANiS
źródło
Możesz również sprawić, by obliczanie przesunięcia zadziałało, włączając do niego scrollLeft i scrollTop.
Ben J
Ale znalazłem offsetLefti offsetTopnie biorę pod uwagę transformacji CSS3, co getBoundingClientRect()robi. Więc to przypadek, że wyniki mogą być nieprawidłowe. Jeśli tego potrzebujesz, możesz uzyskać przesunięcie elementu względem elementu nadrzędnego (jak offsetLeft) za pomocą (element.getBoundingClientRect().left - parent.getBoundingClientRect().left).
Ben J
powinien zdecydowanie wznieść się wyżej; te wartości są znacznie bardziej przydatne, a wszystko to za jednym razem!
mix3d
7

document-offset( Skrypt innej firmy ) jest interesujący i wydaje się, że wykorzystuje podejście z innych odpowiedzi tutaj.

Przykład:

var offset = require('document-offset')
var target = document.getElementById('target')
console.log(offset(target))
// => {top: 69, left: 108} 
Mathieu M-Gosselin
źródło
5

Zauważyłem, że następująca metoda jest najbardziej niezawodna w przypadku skrajnych przypadków, w których dochodzi do potknięcia offsetTop / offsetLeft.

function getPosition(element) {
    var clientRect = element.getBoundingClientRect();
    return {left: clientRect.left + document.body.scrollLeft,
            top: clientRect.top + document.body.scrollTop};
}
Robin Stewart
źródło
4

Dla tych, którzy chcą uzyskać współrzędne x i y różnych pozycji elementu względem dokumentu.

const getCoords = (element, position) => {
  const { top, left, width, height } = element.getBoundingClientRect();
  let point;
  switch (position) {
    case "top left":
      point = {
        x: left + window.pageXOffset,
        y: top + window.pageYOffset
      };
      break;
    case "top center":
      point = {
        x: left + width / 2 + window.pageXOffset,
        y: top + window.pageYOffset
      };
      break;
    case "top right":
      point = {
        x: left + width + window.pageXOffset,
        y: top + window.pageYOffset
      };
      break;
    case "center left":
      point = {
        x: left + window.pageXOffset,
        y: top + height / 2 + window.pageYOffset
      };
      break;
    case "center":
      point = {
        x: left + width / 2 + window.pageXOffset,
        y: top + height / 2 + window.pageYOffset
      };
      break;
    case "center right":
      point = {
        x: left + width + window.pageXOffset,
        y: top + height / 2 + window.pageYOffset
      };
      break;
    case "bottom left":
      point = {
        x: left + window.pageXOffset,
        y: top + height + window.pageYOffset
      };
      break;
    case "bottom center":
      point = {
        x: left + width / 2 + window.pageXOffset,
        y: top + height + window.pageYOffset
      };
      break;
    case "bottom right":
      point = {
        x: left + width + window.pageXOffset,
        y: top + height + window.pageYOffset
      };
      break;
  }
  return point;
};

Stosowanie

  • getCoords(document.querySelector('selector'), 'center')

  • getCoords(document.querySelector('selector'), 'bottom right')

  • getCoords(document.querySelector('selector'), 'top center')

Raphael Rafatpanah
źródło
2

Jeśli nie masz nic przeciwko używaniu jQuery, możesz użyć offset()funkcji. Zapoznaj się z dokumentacją, jeśli chcesz dowiedzieć się więcej o tej funkcji.

Adam
źródło