Bir HTML öğesinin tarayıcı penceresine göre konumunu (X, Y) alın


1568

Tarayıcı penceresine göre JavaScript gibi imgve divJavaScript gibi HTML öğelerinin X ve Y konumlarını nasıl alacağımı bilmek istiyorum .


134
Neye göre?
AnthonyWJones

4
i5,6,7 (ben herhangi bir proboem ... doktor türü olabilir hatırlamıyorum) tüm tutarsızlıkları ile tüm tarayıcılarda çalışan kod 7 satırları kullanıyordum ... quirksmode.org/js/findpos. html ve ben yıllardır çok kullanıyordum. birisi kusurları varsa gösterebilir.
Jayapal Chandran

98
@AnthonyWJones, herhalde bilgiçlikten zevk aldınız, ancak her zaman belirtildiği gibi, OP'nin en genel duruma veya tarayıcının pencere koordinatlarına atıfta bulunduğu açıktır.
Motes

7
@Mote, Hayır, o kadar açık değil. Çıkarım, öznellik ve yanlış aksiyomları bir kenara bırakın. Görünüme veya sayfanın üstüne göre olabilir (belge.documentElement olarak da bilinir).
Andre Figueiredo

15
En genel olanı varsayılan olarak çıkarmak çıkarım değildir, bu mantıksal ilerlemedir, bu yüzden pencereye göreceli olur, ya da "sayfanın üstü" koyduğunuz terim olabilir. Oyun Teorisinde, Schelling noktası adı verilen bir kavram olarak kodlanmıştır. En genel durum anlamına gelmediğini belirttiğinizden emin olun.
Motes

Yanıtlar:


1795

Doğru yaklaşım aşağıdakileri kullanmaktır element.getBoundingClientRect():

var rect = element.getBoundingClientRect();
console.log(rect.top, rect.right, rect.bottom, rect.left);

Internet Explorer bunu umursadığınız ve sonunda CSSOM Görünümlerinde standartlaştırıldığı sürece destekledi . Diğer tüm tarayıcılar bunu uzun zaman önce kabul ettiler .

Bazı tarayıcılar da yükseklik ve genişlik özelliklerini döndürür, ancak bu standart değildir. Daha eski tarayıcı uyumluluğu konusunda endişeleriniz varsa, optimize edilmiş bir düşürme uygulaması için bu yanıtın düzeltmelerini kontrol edin.

Tarafından döndürülen değerler element.getBoundingClientRect()görünüm penceresine göredir. Başka bir öğeye göre buna ihtiyacınız varsa, bir dikdörtgeni diğerinden çıkarın:

var bodyRect = document.body.getBoundingClientRect(),
    elemRect = element.getBoundingClientRect(),
    offset   = elemRect.top - bodyRect.top;

alert('Element is ' + offset + ' vertical pixels from <body>');

143
Bir JS çok ilginç bir yazı koordinatları . Bu makale SO üzerinde hiçbir yerde bahsedilmeyecektir ..
e2-e4

6
Çalışmıyor ... Gövdedeki 8 piksel kenar boşluğu nedeniyle dikey ve yatay olarak 8 piksel çıkıyor. Meouw'un çözümü mükemmel çalışıyor. İsterseniz sorunu göstermek için küçük bir testim var.
CpnCrunch

3
Aslında, bence bu koordinatları almak istediğiniz şeylere bağlıdır. Soru biraz belirsiz. Eğer koordinatları sadece görüntü alanına göre veya gövde elemanına göre istiyorsanız, ancak bu, öğenin mutlak konumunu istediğiniz durumda size yardımcı olmaz (çoğu insanın istediğini hayal ediyorum) . '-scrollLeft' ve '-scrollTop' bitlerini kaldırmazsanız, meouw'un cevabı size bunu vermez.
CpnCrunch

4
@CpnCrunch: Şimdi ne demek istediğini anlıyorum; Cevabımın ikinci kısmına atıfta bulunduğunuzu fark etmedim. Gövde bir kenar boşluğuna sahip olduğunda, sınırlayıcı kutusu her bir taraftaki piksel sayısıyla dengelenir. Bu durumda, hesaplanan kenar boşluğu stilini gövde koordinatlarından da çıkarmanız gerekir. Yine de, CSS sıfırlamalarının marjdan kaldırıldığını belirtmek gerekir <body>.
Andy E

3
element.getBoundingClientRect().topposition: fixedodaklanmış bir giriş öğesi içeriyorsa ve sanal klavye kaydırılmışsa iOS'ta bir öğenin (iPhone 8) doğru üst ofseti döndürmez . Örneğin, pencerenin üst kısmındaki gerçek ofset 200 piksel ise, bunu 420 piksel olarak bildirir, burada 220 piksel sanal klavyenin yüksekliği olur. Elemanları ayarlar position: absoluteve sabitlenmiş konumla aynı konuma yerleştirirseniz, doğru 200 pikseli alırsınız. Buna bir çözüm bilmiyorum.
Jānis Elmeris

327

Kütüphaneler, bir eleman için doğru ofsetleri elde etmek için bazı uzunluklara giderler.
İşte denediğim her koşulda işi yapan basit bir işlev.

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; 

14
değişiklik: el = el.parentNode: el = el.offsetParent; ve şimdi iç içe iframe'ler için işe yarıyor gibi ... Sanırım istediğin bu mu?
Adam

4
Bu çözüm eksik. Bir div'a kalın bir kenarlık koymayı deneyin ve birkaç kez yuvalayın. Firefox'un herhangi bir sürümünde (2-5) sınır genişlik (ler) i tarafından kapatılacaktır (standartlara uygunluk modunda bile).
ck_

3
el.totalOffsetLeft ve totalOffsetTop işlevi gibi bunu yapmanın daha temiz bir yolu yok mu? jQuery kesinlikle bu seçeneğe sahiptir, ancak bunun resmi bir yöntemi olmadığı utanç verici, DOM4'ü beklememiz gerekiyor mu? Bir HTML5 tuval uygulaması oluşturuyorum, bu yüzden en iyi çözüm, element öğesini tıkladığımızda clientX ve clientY ile gerçek koordinatlar alabilmem için bir iframe'e canvas öğesi eklemek olacaktır.
baptx

1
Yani @Adam ve Miyav, ilk kod bloğunun yanlış olduğunu mu söylüyorsun? Öyleyse neden tamamen kaldırmıyorsunuz? (Bu soru yıllar geçtikçe oldukça az sayıda izleyici gördü; eğer yanlışlarsa şeyleri kaldırmak güzel olabilir mi?)
Arjan

2
@baptx: Bunun geç bir yanıt olduğunu biliyorum, ama yorumunu daha önce görmedim. Standartlarla daha uyumlu bir alternatif için aşağıdaki cevabımı görün - tarayıcılar bunu uzun zamandır desteklediğinden, yedek koda bile ihtiyacınız yok.
Andy E

242

Bu benim için çalıştı (en çok oy verilen cevaptan değiştirildi):

function getOffset(el) {
  const rect = el.getBoundingClientRect();
  return {
    left: rect.left + window.scrollX,
    top: rect.top + window.scrollY
  };
}

Bunu kullanarak arayabiliriz

getOffset(element).left

veya

getOffset(element).top

1
Sadece bu çözüm, divcss kullanılarak ortalanmış eleman yerleştirildiğinde benim için çalışıyor top:50%, left:50%; transform:translate(-50%, -50%);... mükemmel. @ScottBiggs sorusu katılıyorum. Mantık, basitliği aramaktır.
nelek

3
belki de kazananı Andy E'nin çözümü ile aynı değildir, ancak eski tarayıcılarda çalışmaz <IE9
niltoid

getBoundingClientRect performans listelerimde büyük bir yeniden
boyamaya

1
Sen tanımlamalıdır rectkullanarak var, letya da const. Aksi takdirde, olarak tanımlanır window.rect.
hev1

2
left: rect.left + window.scrollX + (rect.width / 2), top: rect.top + window.scrollY + (rect.height / 2)bir elementin orta pozisyonunu döndürür
abhishake

97

Eğer sadece javascript olmasını istiyorsan , burada bazıları şunlardır biri gömlekleri kullanarakgetBoundingClientRect()

window.scrollY + document.querySelector('#elementId').getBoundingClientRect().top // Y

window.scrollX + document.querySelector('#elementId').getBoundingClientRect().left // X

İlk satır offsetTopbelgeye göre Y diyecektir. İkinci satır offsetLeftX'e göre belgeye göre dönecektir .

getBoundingClientRect() , pencerenin görünümüne göre öğenin konumunu döndüren bir javascript işlevidir.


2
Çözüm bu olmalı. Burada uzun kod bs yok, anlaşılabilir ve çok doğru!
E Alexis MT

2
öğe kaydırılabilir bir öğenin içindeyse ne olur? Bunu yapmanın tek yolu ofseti toplamaktır.Tüm cevapların önerdiği gibi tüm ana öğelerin
iyisi

Dmitri'nin belirttiği gibi, bu yanlış ve çok kusurlu. En az oyu olmamalıdır. Belgenin kendisi kaydırılabildiğinden DAİMA kaydırılabilir bir öğede de olacaktır. Diğer bir deyişle, belgenin tamamı görünüm penceresine sığmazsa, kullanıcı ana pencereyi kaydırdıysa her zaman yanlış olur.
Lev

46

Çoğu tarayıcıdaki HTML öğelerinde şunlar bulunur: -

offsetLeft
offsetTop

Bunlar, öğenin yerleşime sahip en yakın üst öğeye göre konumunu belirtir. Bu üst öğeye genellikle offsetParent özelliğinde erişilebilir.

IE ve FF3

clientLeft
clientTop

Bu özellikler daha az yaygındır, üst öğe istemci alanı ile bir öğe konumu belirtirler (dolgulu alan istemci alanının bir parçasıdır ancak kenarlık ve kenar boşluğu değildir).


36

Sayfa - en azından herhangi bir "DIV" içeriyorsa, meouw tarafından verilen işlev "Y" değerini geçerli sayfa sınırlarının ötesine atar. Tam konumu bulmak için, hem offsetParent'leri hem de parentNode'ları ele almanız gerekir.

Aşağıda verilen kodu deneyin (FF2 için kontrol edilir):


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

1
FF 24.4 ile bile diğer çözümlerde olduğu gibi, yukarıdaki kod, konumlandırma düzeninin bir parçası olarak sınır genişlikleri olduğunda çalışmaz.
soymak

Sen bir hayat kurtarıcısın. Şu anda bazı oldukça derin GWT hataları üzerinden çalışıyorum ve bir JSNI yönteminde atma tüm sorunları çözer!
Byrne

35

Element.prototypeHerhangi bir öğenin üstünü / solunu almak için iki özellik ekleyebilirsiniz .

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

Buna şöyle denir:

var x = document.getElementById( 'myDiv' ).documentOffsetLeft;

Sonuçları jQuery's offset().topile karşılaştıran bir demo .left: http://jsfiddle.net/ThinkingStiff/3G7EZ/


14
modifikasyon Element.prototypegenellikle kötü bir fikir olarak kabul edilir . Kodun korunması gerçekten zor. Ayrıca, bu kod kaydırmayı hesaba katmaz.
Jared Forsyth

23

Sayfaya göre konumu etkin bir şekilde ve özyinelemeli bir işlev kullanmadan almak için: (IE'yi de içerir)

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;

Tüm önemli scrollTop / scrollLeft'i eklemek bu yanıtı biraz daha doğru hale getirir.
scunliffe

19

Buna benzer bir şeye, öğenin kimliğini ileterek sola veya üste dönecek, bunları da birleştirebiliriz:

1) sola bul

function findLeft(element) {
  var rec = document.getElementById(element).getBoundingClientRect();
  return rec.left + window.scrollX;
} //call it like findLeft('#header');

2) üst bulmak

function findTop(element) {
  var rec = document.getElementById(element).getBoundingClientRect();
  return rec.top + window.scrollY;
} //call it like findTop('#header');

veya 3) sola ve üste birlikte bul

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');

16

Tarayıcıdan bağımsız bir şekilde bu tür bilgileri (ve çok daha fazlasını!) Döndüren işlevlere sahip bir JavaScript çerçevesi kullanarak daha iyi hizmet verebilirsiniz. Burda biraz var:

Bu çerçevelerle, şöyle bir şey yapabilirsiniz: $('id-of-img').top görüntünün y-piksel koordinatını elde etmek için.


2
@Costa Farklı tarayıcılar spesifikasyona farklı bir şekilde uyduğundan, bu gelişmekte olan bir alan olmasına rağmen, hepsi bu tür işlevleri kullanır. Kod çok şey yanlış gider şeyler sabitleme ile ilgilidir. Gerçekten kaynak koduna bakmalısınız.
Şalom Craimer

18
@ scraimer: jQuery ve YUI çerçeveler DEĞİLDİR !!! Bunlar kütüphaneler ! Aynı şey değil. Alıntı yapma jquery.com : "jQuery hızlı, küçük ve zengin özelliklere sahip bir JavaScript kütüphanesidir ." Yuilibrary.com'a atıfta bulunarak (URL'de "sihirli" kelimeyi de görebilirsiniz ...): "YUI, zengin etkileşimli web uygulamaları oluşturmak için ücretsiz, açık kaynaklı bir JavaScript ve CSS kütüphanesidir ."
Sk8erPeter

29
Yani bu basit görev için büyük kütüphaneler mi kullanmalısınız? Gerekli değil. Js ile her şey yapmak istediğimde bu jQuery çözümlerini almaktan nefret ediyorum. jQuery JS değil!
Opptatt Jobber

1
@OpptattJobber Kabul ediyorum ... JQuery javascript değil. Javascript'e dayanır, ancak tamamen farklı bir programlama dilidir.
Nick Manning

5
@NickManning Yeni bir dil değil, DOM için uyumluluk ve performans geçici çözümlerini doğrudan kodunuza yazma zorunluluğunu ortadan kaldıran bir soyutlama katmanı. JQuery kullanmıyorsanız, yine de bir tür soyutlama katmanı kullanmalısınız.
ginman

15

jQuery .offset () , ilk öğenin geçerli koordinatlarını alır veya her öğenin koordinatlarını, belgeye göre eşleşen öğeler kümesinde ayarlar.


Bazı nedenlerle IE'de diğer tarayıcılara kıyasla aynı sonuçları vermiyor. Bence IE'de pencereye göre konum veriyor, bu yüzden kaydırırsanız, IE'de diğerlerine göre farklı sonuçlar elde edeceksiniz
Abdul Rahim Haddad

1
offset (), en azından Android Chrome'da zum ile karıştırılır, bu nedenle işe yaramaz. stackoverflow.com/a/11396681/1691517 zoom toleranslı bir yol gösterir.
Timo Kähkönen

10

@Meouw'un cevabını aldım, sınıra izin veren clientLeft'e ekledim ve üç sürüm oluşturdum:

getAbsoluteOffsetFromBody - @ meouw'lara benzer şekilde, bu belgenin gövdesine veya html öğesine göre mutlak konumu alır (tuhaflık moduna bağlı olarak)

getAbsoluteOffsetFromGivenElement - verilen öğeye (relativeEl) göre mutlak konumu döndürür. Verilen öğenin el öğesini içermesi gerektiğini, aksi takdirde getAbsoluteOffsetFromBody ile aynı şekilde davranacağını unutmayın. Başka bir (bilinen) öğede (isteğe bağlı olarak düğüm ağacının üstündeki birkaç düğüm) bulunan iki öğeniz varsa ve bunları aynı konuma getirmek istiyorsanız bu yararlıdır.

getAbsoluteOffsetFromRelative - position: relative ile ilk üst öğeye göre mutlak konumu döndürür. Bu, aynı nedenle getAbsoluteOffsetFromGivenElement öğesine benzer, ancak yalnızca ilk eşleşen öğeye kadar gider.

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

Özellikle kaydırma ile ilgili hala sorun yaşıyorsanız, http://www.greywyvern.com/?post=331 - getStyle'de tarayıcıların davrandığını varsayarak en az bir şüpheli kod parçasını fark etmeyi deneyebilirsiniz. , ama geri kalanını hiç test etmedim.


İlginç ... ancak Edge'de getAbsoluteOffsetFromBody (element) .top, kaydırırken farklı bir değer döndürür, Chrome'da kaydırdığımda tutarlı kalır. Görünüşe göre Edge kaydırma pozisyonuyla ayarlanıyor. Eleman görünüm dışına kaydırıldığında negatif bir değer elde ederim.
Norman

getAbsoluteOffsetFromRelative günümü yaptı, bootstrap Javascript olmadan bootstrap araç ipucunu çoğaltmak zorunda kaldım, bana çok yardımcı oldu.
Nolyurn

Meouw kullanıcı adlarını değiştirirse, yanıtlamak için bağlantı kurun: stackoverflow.com/a/442474/3654837 . (Bu eski ipliği çarpmak istemiyorum, bu yüzden evet, yorumda
belirtiyorum

8

jQuery kullanıyorsanız, dimension eklentisi mükemmeldir ve tam olarak ne istediğinizi belirtmenize izin verir.

Örneğin

Bağıl pozisyon, mutlak pozisyon, dolgu olmadan mutlak pozisyon, dolgu ile ...

Devam ediyor, diyelim ki yapabileceğiniz çok şey var.

Ayrıca jQuery kullanmanın avantajı, hafif dosya boyutu ve kolay kullanımıdır, daha sonra JavaScript olmadan geri dönmeyeceksiniz.


8

Bu oluşturmayı başardığım en iyi kod (jQuery'nin ofsetinden () farklı olarak iframe'lerde de çalışır). Webkit biraz farklı bir davranış var gibi görünüyor.

Meouw'un yorumuna dayanarak:

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

Eğer gerekeceğini unutmayın jQuerykullanmak $.browser.webkit; navigator.userAgentSaf ile aynı şeyi yapmak için etrafta oynamanız gerekecek JavaScript.
SP

2
$ .browser artık jQuery
Gus'ın

maalesef FF 24.4 ile bile, konumlandırma düzeninin bir parçası olarak sınır genişlikleri olduğunda yukarıdaki kod çalışmaz.
soymak

8

JQuery kullanıyorsanız, bu basit bir çözüm olabilir:

<script>
  var el = $("#element");
  var position = el.position();
  console.log( "left: " + position.left + ", top: " + position.top );
</script>

8

Küçük ve küçük arasındaki fark

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

Örnek bir koordinatlara bakın: http://javascript.info/tutorial/coordinates


Bu maalesef modern bir HTML belgesinde bulabileceğiniz tüm öğeler için geçerli değildir. Gömülü <svg>elemanlar, örneğin, yok offsetLeft, offsetTopve offsetParentözellikleri.
Jonathan Eunice

Sadece DIVya da IMGdeğil SVG. "Bir örnek koordinatlara bakın" görünümü? nesne svg konum çağrı getOffsetRect , bulabilirsiniz deneyin nesne çalışma bağlıdır.
KingRider

7

Bulduğum en temiz yaklaşım, jQuery's tarafından kullanılan tekniğin basitleştirilmiş bir versiyonudur offset. Başladığı diğer cevaplara benzer şekilde getBoundingClientRect; o zaman kullandığı windowve documentElementüzerinde marjı gibi kaydırma konumuna yanı sıra şeyleri ayarlamak için body(genellikle varsayılan).

var rect = el.getBoundingClientRect();
var docEl = document.documentElement;

var rectTop = rect.top + window.pageYOffset - docEl.clientTop;
var rectLeft = rect.left + window.pageXOffset - docEl.clientLeft;


6

Bu, birçok cevabın altında kaybolması muhtemel olsa da, buradaki en iyi çözümler benim için işe yaramıyordu.
Anlayabildiğim kadarıyla diğer cevapların hiçbiri yardımcı olmazdı.

Durum :
HTML5 sayfasında bir üstbilginin içinde bir gezinme öğesi olan bir menü vardı (üstbilgi değil, başka bir öğedeki üstbilgi).
Kullanıcı bir kez kaydırdığında navigasyonun üstüne yapışmasını istedim, ancak bundan önce başlık mutlak konumlandırıldı (bu yüzden biraz başka bir şey kaplayabilirim).
Yukarıdaki çözümler hiçbir zaman bir değişikliği tetiklemedi, çünkü .offsetTop değişmeyecek çünkü bu mutlak konumlandırılmış bir elemandı. Ayrıca .scrollTop özelliği en üstteki öğenin en tepesindeydi ... yani 0'dır ve her zaman 0 olur.
Bu ikisini kullanarak yaptığım herhangi bir test (ve getBoundingClientRect sonuçlarıyla aynı), gezinme çubuğunun üst kısmının görüntülenebilir sayfanın üstüne kaydırılıp kaydırılmadığını (yine, konsolda bildirildiği gibi, aynı sayıları kaydırırken aynı kaldıklarını) söylemez ) oluştu.

Çözüm
Benim için çözüm

window.visualViewport.pageTop

PageTop özelliğinin değeri, ekranın görüntülenebilir bölümünü yansıtır, böylece bir öğenin görüntülenebilir alanın sınırlarına referansta bulunduğunu izlememe izin verir.

Muhtemelen kaydırma ile uğraştığım zaman gereksizdir, kaydırılan öğelerin hareketine programlı olarak yanıt vermek için bu çözümü kullanmayı umuyorum.
Umarım başka birine yardımcı olur.
ÖNEMLİ NOT: Bu şu anda Chrome ve Opera'da çalışıyor ve Firefox'ta (6-2018) çalışmıyor ... Firefox visualViewport'u destekleyene kadar Bu yöntemi kullanmamanızı öneririm (ve umarım yakında yaparlar ... çok şey yapar diğerlerinden daha mantıklı).


GÜNCELLEME:
Bu çözümle ilgili sadece bir not.
Hâlâ keşfettiğim şeyi, "... kaydırılan öğelerin hareketine programlı olarak yanıt verdiği" durumlar için çok değerli buluyorum. uygulanabilir. Sahip olduğum problem için daha iyi çözüm, pozisyonu ayarlamak için CSS kullanmaktı : yapışkaneleman üzerinde. Yapışkan kullanarak javascript kullanmadan üst kısmında bir eleman kalmasını sağlayabilirsiniz (NOT: Bu çalışma, sabit ama çoğu kullanımlar için yapışkan yaklaşım olasılıkla daha üstün olacak kadar eleman değişen etkili bir alışkanlık olduğu kadar zamanlar vardır)

: UPDATE01
Ben fark farklı bir sayfa için, hafif karmaşık bir kaydırma kurulumunda (paralaks artı mesajın bir parçası olarak geçmiş kaydırma öğeleri) bir öğenin konumunu tespit etmek için gerekli bir gereksinimim vardı. Bu senaryoda, aşağıdakilerin bir şeyi ne zaman yapacağımı belirlemek için kullandığım değeri sağladığını fark ettim:

  let bodyElement = document.getElementsByTagName('body')[0];
  let elementToTrack = bodyElement.querySelector('.trackme');
  trackedObjPos = elementToTrack.getBoundingClientRect().top;
  if(trackedObjPos > 264)
  {
    bodyElement.style.cssText = '';
  }

Umarım bu cevap şimdi daha yaygındır.


Bu, cevapları sıralamak için aktif tıkladığınızda çok sayıda cevabın tepesinde olması muhtemeldir
lucchi

@lucchi: D iyi sanırım üstteki metni kaldırabilirim ... yine de bu konuda tekrar oldum ve kendi sorunum için daha iyi bir çözüm bulduğumu fark ettim ... ama cevabım daha fazla daha eksiksiz cevaplara ayak notu. Gereksinimlerimin belki de diğer cevapların benim için işe yaramadığı kadar yaygın olmadığından şüpheleniyorum?
MER

1
Yine de cevabınızı takdir ediyorum, sadece söylemek isteyenler, yeni bir şeyler yazdığınızı bileceklerdir. Yalnız değilsin ....
lucchi

5

Bunu böyle yaptım, bu yüzden eski tarayıcılarla çapraz uyumluydu.

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

JavaScript'teki koordinatlar hakkında daha fazla bilgiyi burada bulabilirsiniz: http://javascript.info/tutorial/coordinates


4

Bir öğenin toplam ofsetini elde etmek için, tüm üst ofsetleri özyinelemeli olarak özetleyebilirsiniz:

function getParentOffsets(el): number {
if (el.offsetParent) {
    return el.offsetParent.offsetTop + getParentOffset(el.offsetParent);
} else {
    return 0;
}
}

bu yardımcı program fonksiyonu ile bir dom öğesinin toplam üst ofseti:

el.offsetTop + getParentOffsets(el);

3
/**
 *
 * @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;
}

Cevabınız için ThinkingStiff'e teşekkür ederiz , bu sadece başka bir versiyonudur.


2

Kullanıcının bir tablo satırında hangi bağlantıyı tıkladığına bağlı olarak bir bootstrap 2 modunu konumlandırmak için Andy E'nin çözümünü başarıyla kullandım. Sayfa bir Goblen 5 sayfasıdır ve aşağıdaki javascript java sayfa sınıfına aktarılmıştır.

javascript:

function setLinkPosition(clientId){
var bodyRect = document.body.getBoundingClientRect(),
elemRect = clientId.getBoundingClientRect(),
offset   = elemRect.top - bodyRect.top;
offset   = offset + 20;
$('#serviceLineModal').css("top", offset);

}

Modsal kodum:

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

Döngüdeki bağlantı:

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

Ve sayfa sınıfındaki java kodu:

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');");
        }
    });
}

Umarım bu birine yardımcı olur, bu yazı yardımcı oldu.


Bu js kodu bana yardımcı oldu, ben birden fazla yer tutucular kullanarak eski bir webforms uygulaması var .aspx sayfaları enjekte ve tüm DOM ağacı whack çünkü ben oluşturmak için bir pop-up kutu appendChild () nasıl anlayamadım birden çok yer tutucu ve yanlış işaretleme ile. Body.getBoundingClientRect () kullanarak daha sonra konumlandırma üst kullanarak ihtiyacım oldu. Teşekkürler.
Brad Martin

1

Çok araştırma ve testten sonra bu işe yarıyor gibi görünüyor

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

bkz. http://jsbin.com/xuvovalifo/edit?html,js,output


1

Sadece bunu orada da atacağımı düşündüm.
Eski tarayıcılarda test edemedim, ancak en son 3'te çalışıyor. :)

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

0

Farklı tarayıcılar kenarlık, dolgu, kenar boşluğu vb. Kesin boyutta istediğiniz her kök öğede belirli bir öğenin üst ve sol konumlarını almak için küçük bir işlev yazdım:

function getTop(root, offset) {
    var rootRect = root.getBoundingClientRect();
    var offsetRect = offset.getBoundingClientRect();
    return offsetRect.top - rootRect.top;
}

Sol pozisyonu geri almak için:

    return offsetRect.left - rootRect.left;

-1

Sola ve Yukarıya göre div pozisyonunu al

  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 

Aşağı ve sağa doğru offset () özellikleri olmadığı için oy kullandım
MacroMan

@MacroMan, kararınıza saygı duyuyorum, ancak metinde zaten "kodun alt ve sağ test edilmediğini" açıkladım. Ayrıca, kodumu çok yakında güncelleyeceğim.
Vishal

Bence el.offsetTopve el.offsetLeft(OP jQuery hakkında bir şey söylemiyor ... Cevabınızın neden jQuery kullandığından emin değilim ...)
mesqueeb
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.