วิธีรับตำแหน่งบนสุดขององค์ประกอบที่สัมพันธ์กับวิวพอร์ตของเบราว์เซอร์


173

ฉันต้องการรับตำแหน่งขององค์ประกอบที่สัมพันธ์กับวิวพอร์ตของเบราว์เซอร์ (วิวพอร์ตที่แสดงหน้านั้นไม่ใช่ทั้งหน้า) สิ่งนี้สามารถทำได้ใน JavaScript

ขอบคุณมาก


2
ฉันคิดว่าคำถามนี้คล้ายกับstackoverflow.com/questions/211703/ซึ่งเป็นคำตอบที่ดีมาก
จาคอบ Runge

1
@ JakobRunge นั่นคือ "ดี" ในปี 2013?
Iulian Onofrei

1
พิจารณาการยอมรับวิธีแก้ปัญหา
Iulian Onofrei

คำตอบ:


305

คำตอบที่มีอยู่ล้าสมัยแล้ว getBoundingClientRect()วิธีการดั้งเดิมได้รับในขณะนี้และทำสิ่งที่คำถามถาม นอกจากนี้ยังรองรับทุกเบราว์เซอร์ (รวมถึง IE 5 ดูเหมือน!)

จากหน้า MDN :

ค่าส่งกลับเป็นวัตถุ TextRectangle ซึ่งประกอบด้วยอ่านอย่างเดียวที่เหลืออยู่บนคุณสมบัติด้านขวาและด้านล่างอธิบายชายแดนกล่องพิกเซลกับด้านบนซ้ายเทียบกับด้านซ้ายบนของวิวพอร์ต

คุณใช้มันอย่างนั้น:

var viewportOffset = el.getBoundingClientRect();
// these are relative to the viewport, i.e. the window
var top = viewportOffset.top;
var left = viewportOffset.left;

3
สิ่งนี้อาจทำงานไม่ถูกต้องเมื่อใช้การซูมเบราว์เซอร์ (Android Chrome) โซลูชันจาก @rism ( ดูด้านล่าง ) ใช้งานได้ในกรณีนี้
Dmitry

4
ดีสำหรับกรณีส่วนใหญ่ แต่ถือว่าเป็นองค์ประกอบที่ไม่ได้อยู่ใน iframe ที่ฝังไว้ใช่ไหม คำถามกำลังถามเกี่ยวกับหน้าต่างของเบราว์เซอร์ el.getBoundingClientRect () จะส่งคืนหน้าต่างสัมพัทธ์ของ iframe ไม่ใช่หน้าต่างเบราว์เซอร์
cakidnyc

6
คำถามกำลังถามเกี่ยวกับหน้าต่างของเบราว์เซอร์
Dmitry Dvornikov

2
@Denilson getBoundingClientRect().topไม่ได้อยู่ใน IE11 ของฉันมันส่งกลับ 0 คุณแก้ปัญหาใด ๆ
Arif

@Arif: ขออภัย แต่ฉันไม่สามารถทำซ้ำปัญหาของคุณ ฉันทดสอบสิ่งนี้บน IE11 และยังได้รับผลลัพธ์: codepen.io/denilsonsa/pen/ypqyXj
Denilson Sá Maia

57

ในกรณีของฉันเพื่อความปลอดภัยในการเลื่อนฉันเพิ่ม window.scroll ลงในสมการ:

var element = document.getElementById('myElement');
var topPos = element.getBoundingClientRect().top + window.scrollY;
var leftPos = element.getBoundingClientRect().left + window.scrollX;

ที่ช่วยให้ฉันได้รับตำแหน่งสัมพัทธ์ที่แท้จริงขององค์ประกอบในเอกสารแม้ว่าจะถูกเลื่อน


2
คุณไม่ควรจะเพิ่มตำแหน่งการเลื่อนแทนการลบมัน?
Iulian Onofrei

ฉันตอบคำตอบแล้ว แต่ยังคง @lulian Onofrei ถูกต้อง โปรดแก้ไข
pmrotule

@Fabio getBoundingClientRect().topไม่ได้อยู่ใน IE11 ของฉันมันคืน 0 คุณแก้ปัญหาใด ๆ
Arif

1
@Arif window.scrollY || window.pageYOffsetอาจปรับปรุงการสนับสนุน
Fabian von Ellerts

@FabianvonEllerts :)
Arif

15

แก้ไข: เพิ่มรหัสลงในบัญชีสำหรับการเลื่อนหน้า

function findPos(id) {
    var node = document.getElementById(id);     
    var curtop = 0;
    var curtopscroll = 0;
    if (node.offsetParent) {
        do {
            curtop += node.offsetTop;
            curtopscroll += node.offsetParent ? node.offsetParent.scrollTop : 0;
        } while (node = node.offsetParent);

        alert(curtop - curtopscroll);
    }
}

อาร์กิวเมนต์ id คือ id ขององค์ประกอบที่คุณต้องการออฟเซ็ต ดัดแปลงมาจากการโพสต์ quirksmode


1
ขอบคุณสำหรับคำตอบของคุณ แต่ฉันคิดว่าคุณเข้าใจผิดคำถามของฉันฉันรู้วิธีที่จะได้รับองค์ประกอบด้านบนของหน้าสิ่งที่ฉันพยายามจะทำคือการได้รับตำแหน่งเมื่อเทียบกับ 'วิวพอร์ต' (เช่นหน้าต่างเบราว์เซอร์ ไม่ใช่เอกสาร)
Waleed Eissa

ขออภัยการใช้งาน 'viewport' ทำให้ฉันแย่ ดังนั้นคุณกำลังบอกว่าคุณต้องการบัญชีสำหรับ Chrome ของเบราว์เซอร์เช่นแถบเครื่องมือบุ๊กมาร์กแถบตำแหน่ง ฯลฯ
Derek Swingley

ไม่เพียงแค่หน้าต่างที่คุณเห็นหน้าเว็บ หากหน้าถูกเลื่อนสิ่งนี้จะแตกต่างจากด้านบนของเอกสารไม่เช่นนั้นจะเหมือนกัน
Waleed Eissa

โอ้เข้าใจแล้ว ไม่แน่ใจว่าจะทำอย่างไร ... จะแก้ไขคำตอบของฉันหากฉันคิดอะไรบางอย่าง
Derek Swingley

ฉันทำรหัสเหนือ uglier เล็กน้อย แต่ใช้งานได้ ... ใช้ offsetParent.scrollTop
Derek

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

ดูเหมือนว่าจะคำนวณจากส่วนบนสุดของเอกสารไม่ใช่วิวพอร์ต
Scott Leonard

6

คุณสามารถลอง:

node.offsetTop - window.scrollY

ใช้งานได้บน Opera พร้อมกำหนดเมตาแท็กวิวพอร์ต


7
หากฉันเข้าใจเอกสารอย่างถูกต้องoffsetTopสัมพันธ์กับองค์ประกอบที่อยู่ใกล้ที่สุด ซึ่งขึ้นอยู่กับโครงสร้างของหน้าซึ่งอาจเป็นองค์ประกอบของรูทหรือไม่ก็ได้
Denilson Sá Maia

5

jQuery ใช้อุปกรณ์นี้อย่างหรูหรา หากคุณดูที่แหล่งของ jQuery offsetคุณจะพบว่านี่เป็นวิธีการใช้งาน:

var rect = elem.getBoundingClientRect();
var win = elem.ownerDocument.defaultView;

return {
    top: rect.top + win.pageYOffset,
    left: rect.left + win.pageXOffset
};

2

ฟังก์ชั่นในหน้านี้จะกลับมาเป็นรูปสี่เหลี่ยมผืนผ้าที่มีพิกัดด้านบนซ้ายความสูงและความกว้างขององค์ประกอบผ่านที่สัมพันธ์กับพอร์ตมุมมองเบราว์เซอร์

    localToGlobal: function( _el ) {
       var target = _el,
       target_width = target.offsetWidth,
       target_height = target.offsetHeight,
       target_left = target.offsetLeft,
       target_top = target.offsetTop,
       gleft = 0,
       gtop = 0,
       rect = {};

       var moonwalk = function( _parent ) {
        if (!!_parent) {
            gleft += _parent.offsetLeft;
            gtop += _parent.offsetTop;
            moonwalk( _parent.offsetParent );
        } else {
            return rect = {
            top: target.offsetTop + gtop,
            left: target.offsetLeft + gleft,
            bottom: (target.offsetTop + gtop) + target_height,
            right: (target.offsetLeft + gleft) + target_width
            };
        }
    };
        moonwalk( target.offsetParent );
        return rect;
}

2
function inViewport(element) {
    let bounds = element.getBoundingClientRect();
    let viewWidth = document.documentElement.clientWidth;
    let viewHeight = document.documentElement.clientHeight;

    if (bounds['left'] < 0) return false;
    if (bounds['top'] < 0) return false;
    if (bounds['right'] > viewWidth) return false;
    if (bounds['bottom'] > viewHeight) return false;

    return true;
}

แหล่ง


1

ขอบคุณสำหรับคำตอบทั้งหมด ดูเหมือนว่า Prototype มีฟังก์ชันที่ใช้ฟังก์ชันนี้ (the page ()) โดยการดูซอร์สโค้ดของฟังก์ชั่นฉันพบว่ามันจะคำนวณตำแหน่งออฟเซ็ตองค์ประกอบที่สัมพันธ์กับหน้า (เช่นบนเอกสาร) จากนั้นลบ scrollTop ออกจากนั้น ดูซอร์สโค้ดของต้นแบบสำหรับรายละเอียดเพิ่มเติม


การตัดสินใจที่ดี. อาจเป็นการดีที่สุดที่จะไปกับห้องสมุดหลักแห่งใดแห่งหนึ่งเนื่องจากพวกเขามีแนวโน้มที่จะให้ผลลัพธ์เดียวกันกับเบราว์เซอร์มากขึ้น หากคุณอยากรู้ตรวจสอบคำตอบของฉัน รหัสนั้นจะทำเช่นนี้ แต่ฉันไม่รู้ว่ามันจะค้างไว้ในเบราว์เซอร์อย่างไร
Derek Swingley

1

ฉันสมมติว่าองค์ประกอบที่มีรหัสbtn1อยู่ในหน้าเว็บและ jQuery ที่รวมอยู่ สิ่งนี้ใช้ได้กับเบราว์เซอร์สมัยใหม่ทั้งหมดของ Chrome, FireFox, IE> = 9 และ Edge jQuery ใช้เพื่อกำหนดตำแหน่งที่สัมพันธ์กับเอกสารเท่านั้น

var screenRelativeTop =  $("#btn1").offset().top - (window.scrollY || 
                                            window.pageYOffset || document.body.scrollTop);

var screenRelativeLeft =  $("#btn1").offset().left - (window.scrollX ||
                                           window.pageXOffset || document.body.scrollLeft);

1
jQuery คือ JavaScript ฉันเชื่อว่าคุณหมายถึง"ไม่ใช่วานิลลา / JS บริสุทธิ์ 100%"
Hungerstar

ใช่นั่นคือสิ่งที่ฉันหมายถึง
นิล

1

บางครั้งgetBoundingClientRect()ค่าคุณสมบัติของวัตถุแสดงเป็น 0 สำหรับ IE ในกรณีที่คุณต้องตั้งค่าdisplay = 'block'องค์ประกอบ คุณสามารถใช้รหัสด้านล่างสำหรับเบราว์เซอร์ทั้งหมดเพื่อรับการชดเชย

ขยายฟังก์ชัน jQuery:

(function($) {
    jQuery.fn.weOffset = function () {
        var de = document.documentElement;
        $(this).css("display", "block");
        var box = $(this).get(0).getBoundingClientRect();
        var top = box.top + window.pageYOffset - de.clientTop;
        var left = box.left + window.pageXOffset - de.clientLeft;
        return { top: top, left: left };
    };
}(jQuery));

การใช้:

var elementOffset = $("#" + elementId).weOffset();
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.