Dapatkan posisi / offset elemen relatif terhadap penampung induk?

125

Saya sudah terbiasa bekerja dengan jQuery. Dalam proyek saya saat ini, bagaimanapun, saya menggunakan zepto.js. Zepto tidak menyediakan fileposition() metode seperti yang jQuery. Zepto hanya datang dengan offset().

Ada ide bagaimana saya bisa mengambil offset wadah relatif terhadap induk dengan js murni atau dengan Zepto?

Matt
sumber
4
Tidak setuju menerima jawaban jQuery (yang bahkan tidak diberi label sebagai jQuery!) Saat mengajukan pertanyaan JavaScript.
Yohanes
@ John, apakah Anda memperhatikan tag zepto?
Supersharp
@Supersharp Gunakan JavaScripttag saat Anda menggunakan JavaScript murni. Jika Anda menggunakan kerangka kerja atau pustaka maka Anda tidak menggunakan JavaScripttag. Jika nama Anda Jeff, saya tidak akan memanggil Anda Sally.
Yohanes
@ John itu opini tapi bukan cara SO bekerja. Silakan baca panduan tag javascript. Dalam hal ini, tag harus digunakan bersama dengan tag perpustakaan.
Supersharp
@Supersharp Yeah SO tidak kompeten seperti itu; inflasi tag literal. 😒︎
Yohanes

Jawaban:

188

Peringatan: jQuery, bukan JavaScript standar

element.offsetLeftdan element.offsetTopmerupakan properti javascript murni untuk menemukan posisi elemen sehubungan dengan ituoffsetParent ; menjadi elemen induk terdekat dengan posisi relativeatauabsolute

Alternatifnya, Anda selalu bisa menggunakan Zepto untuk mendapatkan posisi elemen DAN induknya, dan cukup kurangi keduanya:

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

Ini memiliki keuntungan memberi Anda offset anak relatif terhadap induknya meskipun induk tidak diposisikan.

jackwanders
sumber
9
Elemen diposisikan statictidak diimbangi orang tua.
Esailija
5
jangan gunakan titik koma di dalam tanda kurung kurawal, gunakan koma
Luca Borrione
1
bagaimana dengan posisi tetap? apakah mereka mengimbangi orang tua?
Ayyash
1
Ya, @ Ayya- position fixed juga membuat konteks offset baru
mmmeff
9
@vsync jQuery bukanlah raja segalanya sejak ie9 mencapai EOL pada Januari 2016, kami memiliki pilihan DOM standar di semua browser utama, pelajari js murni. Juga pendapat tentang kerangka kerja apa yang akan digunakan tidak memiliki tempat di SO, karena sangat bergantung pada proyek dan platform target.
Hans Koch
72

di js murni hanya menggunakan offsetLeftdan offsetTopproperti.
Contoh biola: 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>

Fabrizio Calderan
sumber
Terima kasih. Apakah ada juga cara untuk mendapatkan offset ke elemen parent.parent?
matt
2
p.offsetTop + p.parentNode.offsetTopAnda dapat membungkus ini dalam pemanggilan fungsi rekursif seperti yang diusulkan PPK beberapa tahun yang lalu. Anda dapat mengubah fungsi untuk meneruskan jumlah level yang akan naik atau menggunakan pemilih untuk ditiru $(selector).parents(parentSelector). Saya lebih suka solusi ini karena implementasi zepto hanya berfungsi pada browser yang mendukung getBoundingClientsRect- yang tidak dimiliki beberapa ponsel.
Torsten Walter
Saya pikir getBoundingClientsRectdidukung secara luas ... jika ada yang tahu ponsel mana yang tidak mendukungnya, saya akan tertarik (tidak dapat menemukan tabel dukungan untuk ponsel tentang hal itu).
Nobita
Ini mungkin jawaban yang paling benar meskipun tidak diberi tanda. Solusi pribadi saya berubah $(this).offset().leftmenjadi this.offsetLeft.
adjwilli
Ini juga memperbaiki jQuery.position()perilaku yang salah di dalam induk yang ditransformasikan ke 3D, terima kasih banyak!
rassoh
6

Saya melakukannya seperti ini di Internet Explorer.

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

=================== Anda bisa menyebutnya seperti ini

getWindowRelativeOffset(top, inputElement);

Saya fokus pada IE hanya sesuai fokus saya, tetapi hal serupa dapat dilakukan untuk browser lain.

Imran Ansari
sumber
1

Tambahkan offset acara ke elemen induk untuk mendapatkan posisi offset absolut acara.

Sebuah contoh :

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;

    }
}

Jika target peristiwa bukan elemen tempat peristiwa didaftarkan, ia menambahkan offset induk ke offset peristiwa saat ini untuk menghitung nilai offset "Absolut".

Menurut Mozilla Web API: " Properti hanya baca HTMLElement.offsetLeft mengembalikan jumlah piksel yang sudut kiri atas elemen saat ini diimbangi ke kiri dalam simpul HTMLElement.offsetParent. "

Ini sebagian besar terjadi saat Anda mendaftarkan acara pada induk yang berisi beberapa turunan lagi, misalnya: tombol dengan ikon bagian dalam atau rentang teks, li elemen dengan bentang dalam. dll ...

DeiDei
sumber
Bagaimana dengan orang tua dari orang tua? Bagaimana dengan elemen bersarang yang memiliki scrollbar? Bagaimana dengan elemen sebelumnya dengan display: none? Posisi offset dokumen yang sebenarnya hampir tidak mungkin dihitung, namun mesin rendering dapat mengetahuinya. Properti sederhana yang terlalu buruk seperti posisi dokumen tidak pernah dimasukkan dalam DOM.
David Spector
@DavidSpector word
1

Contoh

Jadi, jika kita memiliki elemen anak dengan id "child-element" dan kita ingin mendapatkan posisi kiri / atas relatif terhadap elemen induk, katakanlah div yang memiliki kelas "item-parent", kita akan gunakan kode ini.

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

Plugin Terakhir, untuk plugin yang sebenarnya (dengan beberapa catatan yang menjelaskan apa yang terjadi):

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

Catatan: Anda dapat menggunakan ini di acara mouseClick atau mouseover

$(this).offsetRelative("div.item-parent");
Irshad Khan
sumber
Saya tidak melihat pengguliran diperhitungkan. Ada banyak kasus aneh yang bisa terjadi.
David Spector
1

Saya mendapat Solusi lain. Kurangi nilai properti induk dari nilai properti anak

$('child-div').offset().top - $('parent-div').offset().top;
Irshad Khan
sumber
0

Tentu mudah dengan JS murni, cukup lakukan ini, bekerja untuk panel HTML 5 tetap dan animasi juga, saya membuat dan mencoba kode ini dan berfungsi untuk semua browser (termasuk IE 8):

<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>
Moises Conejo
sumber
Apakah Anda menguji dengan semua kemungkinan kasus node induk dan properti elemen? Apakah akun ini untuk pengguliran dan pengguliran bersarang?
David Spector