Menemukan posisi elemen relatif terhadap dokumen

113

Apa cara termudah untuk menentukan posisi elemen relatif terhadap jendela dokumen / badan / browser?

Saat ini saya menggunakan .offsetLeft/offsetTop, tetapi metode ini hanya memberi Anda posisi relatif terhadap elemen induk, jadi Anda perlu menentukan berapa banyak orang tua ke elemen tubuh, untuk mengetahui posisi yang bergantung pada tubuh / jendela browser / posisi dokumen.

Metode ini juga rumit.

einstein
sumber

Jawaban:

58

Anda dapat melintasi offsetParenthingga tingkat teratas dari DOM.

function getOffsetLeft( elem )
{
    var offsetLeft = 0;
    do {
      if ( !isNaN( elem.offsetLeft ) )
      {
          offsetLeft += elem.offsetLeft;
      }
    } while( elem = elem.offsetParent );
    return offsetLeft;
}
KeatsKelleher
sumber
28
Tidak, jika salah satu induk (terutama elemen html !!!) memiliki margin, paddings atau border.
Flash Thunder
mengenai hal-hal margin ... mungkin membantu untuk mengatur ukuran kotak ke kotak-batas ... atau sesuatu di sepanjang garis itu ... tidak ada yang tidak dapat diperbaiki ...
Pertama, Anda perlu memutuskan apakah akan memperhitungkan batas dan margin sesuai dengan ukuran kotak. Kedua, margin yang runtuh harus dipertimbangkan. Dan terakhir, akan ada situasi yang lebih rumit di masa depan yang akan memperburuk jawaban ini.
xianshenglu
6
Mengapa ini jawaban yang diterima? Ini sudah usang dan berkinerja buruk. Bantulah diri Anda sendiri dan gunakan getBoundingClientRect () seperti yang disarankan dalam jawaban lain.
Fabian von Ellerts
177

Anda bisa mendapatkan posisi atas dan kiri tanpa melintasi DOM seperti ini:

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) };
}
kemangi
sumber
6
Jawaban ini tidak memperhitungkan offset orang tua. Ini hanya relatif terhadap viewport
Nickey
3
@Nickey itu tidak benar — posisi viewport, ditambah pemeriksaan offset scroll, menghasilkan koordinat relatif terhadap seluruh dokumen.
natchiketa
1
Dapat bermasalah pada perangkat seluler stackoverflow.com/a/32623832/962634 Perlu penelitian
basil
1
Mengapa Anda mengurangi clientTop / clientLeft?
Teemoh
1
@Teemoh clientTop / clientLeft sesuai dengan nilai batas pada <html>elemen.
Raphael Rafatpanah
98

Anda dapat menggunakan element.getBoundingClientRect()untuk mengambil posisi elemen yang berhubungan dengan viewport.

Kemudian gunakan document.documentElement.scrollTopuntuk menghitung offset viewport.

Jumlah keduanya akan memberikan posisi elemen relatif terhadap dokumen:

element.getBoundingClientRect().top + document.documentElement.scrollTop
dy_
sumber
10
Relatif dengan viewport tidak sama dengan relatif terhadap dokumen. Jika halaman digulir ke bawah sedikit, maka bagian atas relatif ke viewport akan menjadi angka yang lebih kecil daripada relatif atas ke dokumen.
MrVimes
14
dia mulai relatif terhadap viewport dan menambahkan scrollY untuk mendapatkannya relatif ke dokumen.
Joaquin Cuenca Abela
2
document.documentElement.scrollToptidak bekerja di Safari, gunakan window.scrollYsaja
Fabian von Ellerts
7

Saya sarankan menggunakan

element.getBoundingClientRect()

seperti yang diusulkan di sini, bukan penghitungan offset manual melalui offsetLeft , offsetTop , dan offsetParent . seperti yang diusulkan di sini Dalam beberapa keadaan * traversal manual memberikan hasil yang tidak valid. Lihat Plunker ini: http://plnkr.co/pC8Kgj

* Ketika elemen berada di dalam induk yang dapat digulir dengan pemosisian statis (= default).

HANiS
sumber
Anda juga dapat membuat perhitungan offset bekerja dengan memasukkan scrollLeft dan scrollTop ke dalamnya.
Ben J
Tapi saya menemukan offsetLeftdan offsetToptidak memperhitungkan transformasi CSS3 getBoundingClientRect(). Jadi itu kasus hasilnya mungkin tidak valid. Jika Anda membutuhkannya, Anda bisa mendapatkan elemen offset relatif terhadap induk (like offsetLeft) menggunakan (element.getBoundingClientRect().left - parent.getBoundingClientRect().left).
Ben J
harus def lebih tinggi; nilai-nilai ini jauh lebih berguna, dan semuanya dalam satu panggilan juga!
mix3d
7

document-offset( Skrip pihak ketiga ) menarik dan tampaknya memanfaatkan pendekatan dari jawaban lain di sini.

Contoh:

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

Saya telah menemukan metode berikut untuk menjadi yang paling dapat diandalkan ketika berhadapan dengan kasus tepi yang tersandung offsetTop / offsetLeft.

function getPosition(element) {
    var clientRect = element.getBoundingClientRect();
    return {left: clientRect.left + document.body.scrollLeft,
            top: clientRect.top + document.body.scrollTop};
}
Robin Stewart
sumber
4

Bagi mereka yang ingin mendapatkan koordinat x dan y dari berbagai posisi elemen, relatif terhadap dokumen.

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;
};

Pemakaian

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

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

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

Raphael Rafatpanah
sumber
2

Jika Anda tidak keberatan menggunakan jQuery, maka Anda dapat menggunakan offset()fungsi. Lihat dokumentasi jika Anda ingin membaca lebih lanjut tentang fungsi ini.

Adam
sumber