Üst konteynere göre öğenin konumunu / ofsetini alın?


125

JQuery ile çalışmaya alışkınım. Şu anki projemde zepto.js kullanıyorum. Zepto, jQuery'nin yaptığı position()gibi bir yöntem sağlamaz. Zepto sadece birlikte gelir offset().

Saf js veya Zepto ile bir ebeveyne göre bir konteynerin ofsetini nasıl alabileceğim hakkında bir fikriniz var mı?


4
JavaScript sorusu sorarken jQuery yanıtını (jQuery olarak etiketlenmemiş!) Kabul etmemek.
John

@John, zepto etiketini fark ettiniz mi?
Supersharp

@Supersharp JavaScriptSaf JavaScript kullanırken etiketini kullanın . Eğer bir çerçeveyi veya kitaplığı kullanıyorsanız o zaman do not kullanmak JavaScriptetiketi. İsmin Jeff ise sana Sally demezdim.
John

@John bu bir fikir ama SO nasıl çalıştığı değil. Lütfen javascript etiket kılavuzunu okuyun. Bu durumda kütüphane etiketi ile birlikte kullanılmalıdır.
Supersharp

@Supersharp Evet SO bu kadar beceriksiz; değişmez etiket şişirme. 😒︎
John

Yanıtlar:


188

Uyarı: jQuery, standart JavaScript değil

element.offsetLeftve element.offsetTopbir öğenin kendisine göre konumunu bulmak için kullanılan saf javascript özellikleridir offsetParent; relativeveya konumuna sahip en yakın ana öğe olmakabsolute

Alternatif olarak, bir öğenin VE üst öğesinin konumunu almak için her zaman Zepto'yu kullanabilir ve ikisini çıkarabilirsiniz:

var childPos = obj.offset();
var parentPos = obj.parent().offset();
var childOffset = {
    top: childPos.top - parentPos.top,
    left: childPos.left - parentPos.left
}

Bu, ebeveyn konumlandırılmamış olsa bile size bir çocuğun ebeveynine göre ofsetini verme avantajına sahiptir.


9
Konumlandırılan eleman static, ofset üst öğesi değildir.
Esailija

5
parantez içinde noktalı virgül kullanmayın, virgül kullanın
Luca Borrione

1
peki ya sabit pozisyon? ebeveynleri dengeliyorlar mı?
Ayyash

1
Evet, @ Ayya- pozisyon sabit ayrıca yeni bir ofset bağlamı yaratır
mmmeff

9
@vsync jQuery, ie9 Ocak 2016'da EOL'ye ulaştığından beri hiçbir şeyin kralı değil, tüm büyük tarayıcılarda standartlaştırılmış bir DOM seçimimiz var, saf js öğrenin. Ayrıca, büyük ölçüde projeye ve hedef platforma bağlı olduğundan, hangi çerçevenin kullanılacağına ilişkin görüşlerin SO'da yeri yoktur.
Hans Koch

72

saf js'de sadece kullanım offsetLeftve offsetTopözellikler.
Örnek keman: http://jsfiddle.net/WKZ8P/

var elm = document.querySelector('span');
console.log(elm.offsetLeft, elm.offsetTop);
p   { position:relative; left:10px; top:85px; border:1px solid blue; }
span{ position:relative; left:30px; top:35px; border:1px solid red; }
<p>
    <span>paragraph</span>
</p>


Teşekkür ederim. Bir parent.parent elemanına ofseti almanın bir yolu var mı?
matt

2
p.offsetTop + p.parentNode.offsetTopBunu, PPK'nın birkaç yıl önce önerdiği gibi özyinelemeli bir işlev çağrısına sarabilirsiniz . İşlevi, yukarı çıkılacak düzeylerin sayısını geçecek şekilde değiştirebilir veya taklit etmek için bir seçici kullanabilirsiniz $(selector).parents(parentSelector). Bu çözümü tercih ederim çünkü zepto uygulaması yalnızca destekleyen tarayıcılarda çalışır getBoundingClientsRect- bazı cep telefonlarında bunu yapmaz.
Torsten Walter

getBoundingClientsRectGeniş çapta desteklendiğini sanıyordum ... eğer hangi cep telefonlarının desteklemediğini bilen biri olursa ilgilenirim (cep telefonları için herhangi bir destek tablosu bulamıyorum).
Nobita

Bu, işaretlenmemiş olmasına rağmen muhtemelen en doğru cevaptır. Benim kişisel çözüm değişiyordu $(this).offset().leftiçin this.offsetLeft.
adjwilli

Bu aynı zamanda jQuery.position()3 boyutlu dönüştürülmüş bir ebeveynin içindeki yanlış davranışı da düzeltir , çok teşekkür ederim!
rassoh

6

Bunu Internet Explorer'da böyle yaptım.

function getWindowRelativeOffset(parentWindow, elem) {
    var offset = {
        left : 0,
        top : 0
    };
    // relative to the target field's document
    offset.left = elem.getBoundingClientRect().left;
    offset.top = elem.getBoundingClientRect().top;
    // now we will calculate according to the current document, this current
    // document might be same as the document of target field or it may be
    // parent of the document of the target field
    var childWindow = elem.document.frames.window;
    while (childWindow != parentWindow) {
        offset.left = offset.left + childWindow.frameElement.getBoundingClientRect().left;
        offset.top = offset.top + childWindow.frameElement.getBoundingClientRect().top;
        childWindow = childWindow.parent;
    }

    return offset;
};

=================== buna böyle diyebilirsiniz

getWindowRelativeOffset(top, inputElement);

IE'ye yalnızca odaklandığım için odaklanıyorum, ancak diğer tarayıcılar için benzer şeyler yapılabilir.


1

Olayın mutlak ofset konumunu elde etmek için, olayın ofsetini üst öğe ofsetine ekleyin.

Bir örnek :

HTMLElement.addEventListener('mousedown',function(e){

    var offsetX = e.offsetX;
    var offsetY = e.offsetY;

    if( e.target != this ){ // 'this' is our HTMLElement

        offsetX = e.target.offsetLeft + e.offsetX;
        offsetY = e.target.offsetTop + e.offsetY;

    }
}

Olay hedefi, olayın kaydedildiği öğe olmadığında, "Mutlak" ofset değerini hesaplamak için üst öğenin ofsetini mevcut olay ofsetine ekler.

Mozilla Web API'sine göre: " HTMLElement.offsetLeft salt okunur özelliği, geçerli öğenin sol üst köşesinin HTMLElement.offsetParent düğümü içinde sola kaydırıldığı piksel sayısını döndürür . "

Bu çoğunlukla, birkaç çocuk daha içeren bir ebeveyne kaydettiğinizde olur, örneğin: iç simgeye veya metin aralığına sahip bir düğme, iç açıklıkları olan bir liöğe. vb...


Ya ebeveynin ebeveyni? Kaydırma çubuklarına sahip iç içe geçmiş öğeler ne olacak? Peki ekranlı önceki öğeler: yok mu? Gerçek bir belge ofset pozisyonunu hesaplamak neredeyse imkansızdır, ancak işleme motoru bunu bilebilir. Belge konumu gibi çok kötü basit özellikler hiçbir zaman DOM'a dahil edilmedi.
David Spector

@DavidSpector word

1

Misal

Dolayısıyla, "alt öğe" kimliğine sahip bir alt öğemiz olsaydı ve bunun bir üst öğeye, örneğin "öğe-üst" sınıfına sahip bir div öğesine göre sol / üst konumunu elde etmek istersek, bu kodu kullanın.

var position = $("#child-element").offsetRelative("div.item-parent");
alert('left: '+position.left+', top: '+position.top);

Eklenti Son olarak, gerçek eklenti için (neler olup bittiğini açıklayan birkaç notla):

// offsetRelative (or, if you prefer, positionRelative)
(function($){
    $.fn.offsetRelative = function(top){
        var $this = $(this);
        var $parent = $this.offsetParent();
        var offset = $this.position();
        if(!top) return offset; // Didn't pass a 'top' element 
        else if($parent.get(0).tagName == "BODY") return offset; // Reached top of document
        else if($(top,$parent).length) return offset; // Parent element contains the 'top' element we want the offset to be relative to 
        else if($parent[0] == $(top)[0]) return offset; // Reached the 'top' element we want the offset to be relative to 
        else { // Get parent's relative offset
            var parent_offset = $parent.offsetRelative(top);
            offset.top += parent_offset.top;
            offset.left += parent_offset.left;
            return offset;
        }
    };
    $.fn.positionRelative = function(top){
        return $(this).offsetRelative(top);
    };
}(jQuery));

Not: Sen KullanabileceğinizAnalytics bu mouseClick veya mouseover Olay üzerine

$(this).offsetRelative("div.item-parent");

Kaydırmanın hesaba katıldığını görmüyorum. Olabilecek birçok garip durum var.
David Spector

1

Başka bir Çözüm buldum. Üst mülk değerini alt mülk değerinden çıkarın

$('child-div').offset().top - $('parent-div').offset().top;

0

Saf JS ile kesinlikle kolaydır, sadece bunu yapın, sabit ve hareketli HTML 5 panelleri için de çalışın, bu kodu yaptım ve denedim ve herhangi bir tarayıcı için çalışıyor (IE 8 dahil):

<script type="text/javascript">
    function fGetCSSProperty(s, e) {
        try { return s.currentStyle ? s.currentStyle[e] : window.getComputedStyle(s)[e]; }
        catch (x) { return null; } 
    }
    function fGetOffSetParent(s) {
        var a = s.offsetParent || document.body;

        while (a && a.tagName && a != document.body && fGetCSSProperty(a, 'position') == 'static')
            a = a.offsetParent;
        return a;
    }
    function GetPosition(s) {
        var b = fGetOffSetParent(s);

        return { Left: (b.offsetLeft + s.offsetLeft), Top: (b.offsetTop + s.offsetTop) };
    }    
</script>

Tüm olası ana düğüm durumları ve eleman özellikleri ile test ettiniz mi? Bu, kaydırma ve iç içe kaydırmayı hesaba katar mı?
David Spector
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.