Saya ingin tahu cara mendapatkan posisi X dan Y elemen HTML seperti img
dan div
dalam JavaScript relatif ke jendela browser.
Saya ingin tahu cara mendapatkan posisi X dan Y elemen HTML seperti img
dan div
dalam JavaScript relatif ke jendela browser.
Jawaban:
Pendekatan yang benar adalah dengan menggunakan element.getBoundingClientRect()
:
var rect = element.getBoundingClientRect();
console.log(rect.top, rect.right, rect.bottom, rect.left);
Internet Explorer telah mendukung ini sejak Anda cenderung peduli dan akhirnya standar di Tampilan CSSOM . Semua browser lain sudah lama menggunakannya .
Beberapa browser juga mengembalikan properti tinggi dan lebar, meskipun ini tidak standar. Jika Anda khawatir tentang kompatibilitas browser yang lebih lama, periksa revisi jawaban ini untuk penerapan penurunan yang dioptimalkan.
Nilai yang dikembalikan element.getBoundingClientRect()
relatif terhadap viewport. Jika Anda membutuhkannya relatif terhadap elemen lain, cukup kurangi satu persegi panjang dari yang lain:
var bodyRect = document.body.getBoundingClientRect(),
elemRect = element.getBoundingClientRect(),
offset = elemRect.top - bodyRect.top;
alert('Element is ' + offset + ' vertical pixels from <body>');
<body>
, meskipun.
element.getBoundingClientRect().top
tidak mengembalikan offset atas yang benar jika ada position: fixed
elemen di iOS (iPhone 8) jika mengandung elemen input terfokus dan keyboard virtual telah meluncur. Misalnya, jika offset aktual dari bagian atas jendela adalah 200px, itu akan melaporkannya sebagai 420px, di mana 220px adalah ketinggian keyboard virtual. Jika Anda mengatur elemen position: absolute
dan memposisikannya pada posisi yang sama seperti jika diperbaiki, maka Anda akan mendapatkan 200px yang benar. Saya tidak tahu solusi untuk ini.
Perpustakaan berusaha keras untuk mendapatkan offset yang akurat untuk suatu elemen.
inilah fungsi sederhana yang melakukan pekerjaan dalam setiap keadaan yang telah saya coba.
function getOffset( el ) {
var _x = 0;
var _y = 0;
while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {
_x += el.offsetLeft - el.scrollLeft;
_y += el.offsetTop - el.scrollTop;
el = el.offsetParent;
}
return { top: _y, left: _x };
}
var x = getOffset( document.getElementById('yourElId') ).left;
Ini bekerja untuk saya (dimodifikasi dari jawaban pilihan tertinggi):
function getOffset(el) {
const rect = el.getBoundingClientRect();
return {
left: rect.left + window.scrollX,
top: rect.top + window.scrollY
};
}
Dengan ini kita bisa menelepon
getOffset(element).left
atau
getOffset(element).top
div
yang berpusat menggunakan css top:50%, left:50%; transform:translate(-50%, -50%);
... sangat baik. Setuju dengan pertanyaan @ScottBiggs. Logis adalah mencari kesederhanaan.
rect
menggunakan var
, let
atau const
. Kalau tidak, itu didefinisikan sebagai window.rect
.
left: rect.left + window.scrollX + (rect.width / 2), top: rect.top + window.scrollY + (rect.height / 2)
akan mengembalikan posisi tengah elemen
Jika Anda ingin melakukannya hanya dalam javascript , berikut adalah beberapa baris yang digunakangetBoundingClientRect()
window.scrollY + document.querySelector('#elementId').getBoundingClientRect().top // Y
window.scrollX + document.querySelector('#elementId').getBoundingClientRect().left // X
Baris pertama akan mengembalikan offsetTop
say Y relatif ke dokumen. Baris kedua akan mengembalikan offsetLeft
katakan X relatif terhadap dokumen.
getBoundingClientRect()
adalah fungsi javascript yang mengembalikan posisi elemen relatif ke viewport jendela.
Elemen HTML pada sebagian besar browser akan memiliki: -
offsetLeft
offsetTop
Ini menentukan posisi elemen relatif orang tua terdekatnya yang memiliki tata letak. Induk ini sering dapat diakses jika properti offsetParent.
IE dan FF3 miliki
clientLeft
clientTop
Properti ini kurang umum, mereka menentukan posisi elemen dengan area klien orang tuanya (area empuk adalah bagian dari area klien tetapi batas dan margin tidak).
Jika halaman menyertakan - setidaknya- "DIV" apa saja, fungsi yang diberikan oleh meouw melempar nilai "Y" melampaui batas halaman saat ini. Untuk menemukan posisi yang tepat, Anda harus menangani offsetParent dan parentNode.
Coba kode yang diberikan di bawah ini (diperiksa untuk FF2):
var getAbsPosition = function(el){
var el2 = el;
var curtop = 0;
var curleft = 0;
if (document.getElementById || document.all) {
do {
curleft += el.offsetLeft-el.scrollLeft;
curtop += el.offsetTop-el.scrollTop;
el = el.offsetParent;
el2 = el2.parentNode;
while (el2 != el) {
curleft -= el2.scrollLeft;
curtop -= el2.scrollTop;
el2 = el2.parentNode;
}
} while (el.offsetParent);
} else if (document.layers) {
curtop += el.y;
curleft += el.x;
}
return [curtop, curleft];
};
Anda dapat menambahkan dua properti Element.prototype
untuk mendapatkan bagian atas / kiri elemen apa pun.
Object.defineProperty( Element.prototype, 'documentOffsetTop', {
get: function () {
return this.offsetTop + ( this.offsetParent ? this.offsetParent.documentOffsetTop : 0 );
}
} );
Object.defineProperty( Element.prototype, 'documentOffsetLeft', {
get: function () {
return this.offsetLeft + ( this.offsetParent ? this.offsetParent.documentOffsetLeft : 0 );
}
} );
Ini disebut seperti ini:
var x = document.getElementById( 'myDiv' ).documentOffsetLeft;
Berikut ini adalah demo yang membandingkan hasilnya dengan jQuery offset().top
dan .left
: http://jsfiddle.net/ThinkingStiff/3G7EZ/
Element.prototype
umumnya dianggap ide yang buruk . Itu menyebabkan sangat sulit untuk mempertahankan kode. Selain itu, kode ini tidak memperhitungkan pengguliran.
Untuk mengambil posisi relatif terhadap halaman secara efisien, dan tanpa menggunakan fungsi rekursif: (termasuk IE juga)
var element = document.getElementById('elementId'); //replace elementId with your element's Id.
var rect = element.getBoundingClientRect();
var elementLeft,elementTop; //x and y
var scrollTop = document.documentElement.scrollTop?
document.documentElement.scrollTop:document.body.scrollTop;
var scrollLeft = document.documentElement.scrollLeft?
document.documentElement.scrollLeft:document.body.scrollLeft;
elementTop = rect.top+scrollTop;
elementLeft = rect.left+scrollLeft;
Bagaimana dengan sesuatu seperti ini, dengan melewati ID elemen dan itu akan mengembalikan kiri atau atas, kita juga dapat menggabungkan mereka:
1) temukan kiri
function findLeft(element) {
var rec = document.getElementById(element).getBoundingClientRect();
return rec.left + window.scrollX;
} //call it like findLeft('#header');
2) temukan top
function findTop(element) {
var rec = document.getElementById(element).getBoundingClientRect();
return rec.top + window.scrollY;
} //call it like findTop('#header');
atau 3) temukan kiri dan atas bersamaan
function findTopLeft(element) {
var rec = document.getElementById(element).getBoundingClientRect();
return {top: rec.top + window.scrollY, left: rec.left + window.scrollX};
} //call it like findTopLeft('#header');
Anda mungkin lebih baik dilayani dengan menggunakan kerangka kerja JavaScript, yang memiliki fungsi untuk mengembalikan informasi tersebut (dan banyak lagi!) Dengan cara yang tidak tergantung pada browser. Berikut ini beberapa di antaranya:
Dengan kerangka kerja ini, Anda dapat melakukan sesuatu seperti:
$('id-of-img').top
untuk mendapatkan koordinat y-pixel dari gambar.
jQuery .offset () akan mendapatkan koordinat saat ini dari elemen pertama, atau mengatur koordinat setiap elemen, di set elemen yang cocok, relatif terhadap dokumen.
Saya telah mengambil jawaban @ meouw, ditambahkan di clientLeft yang memungkinkan untuk perbatasan, dan kemudian membuat tiga versi:
getAbsoluteOffsetFromBody - mirip dengan @ meouw, ini mendapatkan posisi absolut relatif terhadap elemen tubuh atau html dokumen (tergantung pada mode quirks)
getAbsoluteOffsetFromGivenElement - mengembalikan posisi absolut relatif terhadap elemen yang diberikan (relatifEl). Perhatikan bahwa elemen yang diberikan harus mengandung elemen el, atau ini akan berperilaku sama dengan getAbsoluteOffsetFromBody. Ini berguna jika Anda memiliki dua elemen yang terkandung di dalam elemen (dikenal) lainnya (opsional beberapa node di atas simpul pohon) dan ingin menjadikannya posisi yang sama.
getAbsoluteOffsetFromRelative - mengembalikan posisi absolut relatif ke elemen induk pertama dengan posisi: relatif. Ini mirip dengan getAbsoluteOffsetFromGivenElement, untuk alasan yang sama tetapi hanya akan sejauh elemen pencocokan pertama.
getAbsoluteOffsetFromBody = function( el )
{ // finds the offset of el from the body or html element
var _x = 0;
var _y = 0;
while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) )
{
_x += el.offsetLeft - el.scrollLeft + el.clientLeft;
_y += el.offsetTop - el.scrollTop + el.clientTop;
el = el.offsetParent;
}
return { top: _y, left: _x };
}
getAbsoluteOffsetFromGivenElement = function( el, relativeEl )
{ // finds the offset of el from relativeEl
var _x = 0;
var _y = 0;
while( el && el != relativeEl && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) )
{
_x += el.offsetLeft - el.scrollLeft + el.clientLeft;
_y += el.offsetTop - el.scrollTop + el.clientTop;
el = el.offsetParent;
}
return { top: _y, left: _x };
}
getAbsoluteOffsetFromRelative = function( el )
{ // finds the offset of el from the first parent with position: relative
var _x = 0;
var _y = 0;
while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) )
{
_x += el.offsetLeft - el.scrollLeft + el.clientLeft;
_y += el.offsetTop - el.scrollTop + el.clientTop;
el = el.offsetParent;
if (el != null)
{
if (getComputedStyle !== 'undefined')
valString = getComputedStyle(el, null).getPropertyValue('position');
else
valString = el.currentStyle['position'];
if (valString === "relative")
el = null;
}
}
return { top: _y, left: _x };
}
Jika Anda masih mengalami masalah, terutama yang berkaitan dengan pengguliran, Anda dapat mencoba melihat http://www.greywyvern.com/?post=331 - Saya perhatikan setidaknya satu potong kode yang dipertanyakan di getStyle yang seharusnya baik-baik saja dengan asumsi browser berperilaku , tetapi belum menguji sisanya sama sekali.
jika menggunakan jQuery, plugin dimensi sangat bagus dan memungkinkan Anda menentukan dengan tepat apa yang Anda inginkan.
misalnya
Posisi relatif, posisi absolut, posisi absolut tanpa bantalan, dengan bantalan ...
Terus, katakan saja ada banyak yang bisa Anda lakukan dengannya.
Plus bonus menggunakan jQuery adalah ukuran file yang ringan dan mudah digunakan, Anda tidak akan kembali ke JavaScript tanpa itu sesudahnya.
Ini adalah kode terbaik yang berhasil saya buat (berfungsi di iframe juga, tidak seperti offset jQuery ()). Sepertinya webkit memiliki sedikit perilaku yang berbeda.
Berdasarkan komentar meouw:
function getOffset( el ) {
var _x = 0;
var _y = 0;
while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {
_x += el.offsetLeft - el.scrollLeft;
_y += el.offsetTop - el.scrollTop;
// chrome/safari
if ($.browser.webkit) {
el = el.parentNode;
} else {
// firefox/IE
el = el.offsetParent;
}
}
return { top: _y, left: _x };
}
Jika Anda menggunakan jQuery, ini bisa menjadi solusi sederhana:
<script>
var el = $("#element");
var position = el.position();
console.log( "left: " + position.left + ", top: " + position.top );
</script>
Perbedaan antara kecil dan kecil
function getPosition( el ) {
var x = 0;
var y = 0;
while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {
x += el.offsetLeft - el.scrollLeft;
y += el.offsetTop - el.scrollTop;
el = el.offsetParent;
}
return { top: y, left: x };
}
Lihat contoh koordinat: http://javascript.info/tutorial/coordinates
<svg>
elemen, misalnya, tidak memiliki offsetLeft
, offsetTop
, dan offsetParent
properti.
DIV
atau IMG
tidak SVG
. Lihat "Lihat contoh koordinat"? Anda dapat menemukan objek svg adalah panggilan posisi getOffsetRect , mencoba dan bergantung pada objek.
Pendekatan terbersih yang saya temukan adalah versi sederhana dari teknik yang digunakan oleh jQuery offset
. Mirip dengan beberapa jawaban lain yang dimulai dengan getBoundingClientRect
; kemudian menggunakan window
dan documentElement
untuk menyesuaikan posisi gulir serta hal-hal seperti margin pada body
(seringkali default).
var rect = el.getBoundingClientRect();
var docEl = document.documentElement;
var rectTop = rect.top + window.pageYOffset - docEl.clientTop;
var rectLeft = rect.left + window.pageXOffset - docEl.clientLeft;
Meskipun ini sangat mungkin hilang di bagian bawah dari begitu banyak jawaban, solusi teratas di sini tidak bekerja untuk saya.
Sejauh yang saya tahu, tidak ada jawaban lain yang akan membantu.
Situasi :
Di halaman HTML5 saya memiliki menu yang merupakan elemen nav di dalam header (bukan header tetapi header di elemen lain).
Saya ingin navigasi untuk tetap di atas setelah pengguna menggulir ke sana, tapi sebelumnya header ini diposisikan absolut (jadi saya bisa sedikit overlay sesuatu yang lain).
Solusi di atas tidak pernah memicu perubahan karena .offsetTop tidak akan berubah karena ini adalah elemen yang diposisikan mutlak. Selain itu, properti .scrollTop hanyalah bagian atas elemen paling atas ... yaitu 0 dan selalu 0.
Setiap tes yang saya lakukan menggunakan kedua (dan sama dengan hasil getBoundingClientRect) tidak akan memberi tahu saya jika bagian atas bilah navigasi pernah menggulir ke bagian atas halaman yang dapat dilihat (sekali lagi, seperti yang dilaporkan dalam konsol, mereka hanya tinggal nomor yang sama saat menggulir terjadi).
Solusi
Solusi bagi saya adalah memanfaatkan
window.visualViewport.pageTop
Nilai properti pageTop mencerminkan bagian layar yang dapat dilihat, oleh karena itu memungkinkan saya untuk melacak di mana elemen mengacu pada batas-batas area yang dapat dilihat.
Mungkin tidak perlu dikatakan, kapan pun saya berurusan dengan pengguliran, saya berharap untuk menggunakan solusi ini untuk merespons secara sistematis terhadap pergerakan elemen yang sedang digulir.
Semoga ini bisa membantu orang lain.
CATATAN PENTING: Ini tampaknya berfungsi di Chrome dan Opera saat ini & pasti tidak di Firefox (6-2018) ... sampai Firefox mendukung visualViewport Saya sarankan TIDAK menggunakan metode ini, (dan saya harap mereka segera melakukannya ... itu membuat banyak lebih masuk akal daripada yang lain).
UPDATE:
Hanya sebuah catatan mengenai solusi ini.
Sementara saya masih menemukan apa yang saya temukan sangat berharga untuk situasi di mana "... terprogram merespons pergerakan elemen yang sedang digulir." berlaku. Solusi yang lebih baik untuk masalah yang saya miliki adalah menggunakan CSS untuk mengatur posisi: stickypada elemen. Menggunakan sticky Anda dapat memiliki elemen tetap di atas tanpa menggunakan javascript (CATATAN: ada kalanya ini tidak akan bekerja seefektif mengubah elemen untuk diperbaiki tetapi untuk sebagian besar menggunakan pendekatan sticky kemungkinan akan lebih unggul)
UPDATE01:
Jadi saya menyadari bahwa untuk halaman yang berbeda saya memiliki persyaratan di mana saya perlu mendeteksi posisi elemen dalam pengaturan pengguliran yang agak rumit (paralaks plus elemen yang menggulir melewati sebagai bagian dari pesan). Saya menyadari dalam skenario itu bahwa berikut ini memberikan nilai yang saya gunakan untuk menentukan kapan harus melakukan sesuatu:
let bodyElement = document.getElementsByTagName('body')[0];
let elementToTrack = bodyElement.querySelector('.trackme');
trackedObjPos = elementToTrack.getBoundingClientRect().top;
if(trackedObjPos > 264)
{
bodyElement.style.cssText = '';
}
Semoga jawaban ini lebih bermanfaat sekarang.
Saya melakukannya seperti ini sehingga kompatibel dengan browser lama.
// For really old browser's or incompatible ones
function getOffsetSum(elem) {
var top = 0,
left = 0,
bottom = 0,
right = 0
var width = elem.offsetWidth;
var height = elem.offsetHeight;
while (elem) {
top += elem.offsetTop;
left += elem.offsetLeft;
elem = elem.offsetParent;
}
right = left + width;
bottom = top + height;
return {
top: top,
left: left,
bottom: bottom,
right: right,
}
}
function getOffsetRect(elem) {
var box = elem.getBoundingClientRect();
var body = document.body;
var docElem = document.documentElement;
var scrollTop = window.pageYOffset || docElem.scrollTop || body.scrollTop;
var scrollLeft = window.pageXOffset || docElem.scrollLeft || body.scrollLeft;
var clientTop = docElem.clientTop;
var clientLeft = docElem.clientLeft;
var top = box.top + scrollTop - clientTop;
var left = box.left + scrollLeft - clientLeft;
var bottom = top + (box.bottom - box.top);
var right = left + (box.right - box.left);
return {
top: Math.round(top),
left: Math.round(left),
bottom: Math.round(bottom),
right: Math.round(right),
}
}
function getOffset(elem) {
if (elem) {
if (elem.getBoundingClientRect) {
return getOffsetRect(elem);
} else { // old browser
return getOffsetSum(elem);
}
} else
return null;
}
Lebih lanjut tentang koordinat dalam JavaScript di sini: http://javascript.info/tutorial/coordinates
Untuk mendapatkan total offset elemen, Anda bisa meringkas semua offset induk secara rekursif:
function getParentOffsets(el): number {
if (el.offsetParent) {
return el.offsetParent.offsetTop + getParentOffset(el.offsetParent);
} else {
return 0;
}
}
dengan fungsi utilitas ini offset total atas elemen dom adalah:
el.offsetTop + getParentOffsets(el);
/**
*
* @param {HTMLElement} el
* @return {{top: number, left: number}}
*/
function getDocumentOffsetPosition(el) {
var position = {
top: el.offsetTop,
left: el.offsetLeft
};
if (el.offsetParent) {
var parentPosition = getDocumentOffsetPosition(el.offsetParent);
position.top += parentPosition.top;
position.left += parentPosition.left;
}
return position;
}
Terima kasih ThinkingStiff atas jawabannya , ini hanya versi lain.
Saya berhasil menggunakan solusi Andy E untuk memposisikan modal bootstrap 2 tergantung pada tautan apa di baris tabel yang diklik pengguna. Halaman ini adalah halaman Tapestry 5 dan javascript di bawah ini diimpor dalam kelas halaman java.
javascript:
function setLinkPosition(clientId){
var bodyRect = document.body.getBoundingClientRect(),
elemRect = clientId.getBoundingClientRect(),
offset = elemRect.top - bodyRect.top;
offset = offset + 20;
$('#serviceLineModal').css("top", offset);
}
Kode modal saya:
<div id="serviceLineModal" class="modal hide fade add-absolute-position" data-backdrop="static"
tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" style="top:50%;">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button>
<h3 id="myModalLabel">Modal header</h3>
</div>
<div class="modal-body">
<t:zone t:id="modalZone" id="modalZone">
<p>You selected service line number: ${serviceLineNumberSelected}</p>
</t:zone>
</div>
<div class="modal-footer">
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
<!-- <button class="btn btn-primary">Save changes</button> -->
</div>
Tautan di loop:
<t:loop source="servicesToDisplay" value="service" encoder="encoder">
<tr style="border-right: 1px solid black;">
<td style="white-space:nowrap;" class="add-padding-left-and-right no-border">
<a t:type="eventLink" t:event="serviceLineNumberSelected" t:context="service.serviceLineNumber"
t:zone="pageZone" t:clientId="modalLink${service.serviceLineNumber}"
onmouseover="setLinkPosition(this);">
<i class="icon-chevron-down"></i> <!-- ${service.serviceLineNumber} -->
</a>
</td>
Dan kode java di kelas halaman:
void onServiceLineNumberSelected(String number){
checkForNullSession();
serviceLineNumberSelected = number;
addOpenServiceLineDialogCommand();
ajaxResponseRenderer.addRender(modalZone);
}
protected void addOpenServiceLineDialogCommand() {
ajaxResponseRenderer.addCallback(new JavaScriptCallback() {
@Override
public void run(JavaScriptSupport javascriptSupport) {
javascriptSupport.addScript("$('#serviceLineModal').modal('show');");
}
});
}
Semoga ini bisa membantu seseorang, posting ini membantu.
Setelah banyak penelitian dan pengujian, ini tampaknya berhasil
function getPosition(e) {
var isNotFirefox = (navigator.userAgent.toLowerCase().indexOf('firefox') == -1);
var x = 0, y = 0;
while (e) {
x += e.offsetLeft - e.scrollLeft + (isNotFirefox ? e.clientLeft : 0);
y += e.offsetTop - e.scrollTop + (isNotFirefox ? e.clientTop : 0);
e = e.offsetParent;
}
return { x: x + window.scrollX, y: y + window.scrollY };
}
Hanya berpikir saya akan membuang ini di sana juga.
Saya belum bisa mengujinya di browser yang lebih lama, tetapi ia bekerja di yang terbaru dari atas 3. :)
Element.prototype.getOffsetTop = function() {
return ( this.parentElement )? this.offsetTop + this.parentElement.getOffsetTop(): this.offsetTop;
};
Element.prototype.getOffsetLeft = function() {
return ( this.parentElement )? this.offsetLeft + this.parentElement.getOffsetLeft(): this.offsetLeft;
};
Element.prototype.getOffset = function() {
return {'left':this.getOffsetLeft(),'top':this.getOffsetTop()};
};
Karena browser yang berbeda memberikan batas, padding, margin, dll dengan cara yang berbeda. Saya menulis sedikit fungsi untuk mengambil posisi atas dan kiri elemen tertentu di setiap elemen root yang Anda inginkan dalam dimensi yang tepat:
function getTop(root, offset) {
var rootRect = root.getBoundingClientRect();
var offsetRect = offset.getBoundingClientRect();
return offsetRect.top - rootRect.top;
}
Untuk mengambil posisi kiri, Anda harus kembali:
return offsetRect.left - rootRect.left;
Dapatkan posisi div sehubungan dengan kiri dan Atas
var elm = $('#div_id'); //get the div
var posY_top = elm.offset().top; //get the position from top
var posX_left = elm.offset().left; //get the position from left
el.offsetTop
dan el.offsetLeft
(OP tidak mengatakan apa pun tentang jQuery ... Saya juga tidak yakin mengapa jawaban Anda menggunakan jQuery ...)