ใช้ jquery เพื่อรับตำแหน่งขององค์ประกอบที่สัมพันธ์กับวิวพอร์ต


117

อะไรคือวิธีที่เหมาะสมในการรับตำแหน่งขององค์ประกอบบนเพจที่สัมพันธ์กับวิวพอร์ต (แทนที่จะเป็นเอกสาร) jQuery.offsetฟังก์ชั่นดูเหมือนมีแนวโน้ม:

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

แต่นั่นสัมพันธ์กับเอกสาร มีวิธีการเทียบเท่าที่ส่งคืนค่าชดเชยที่สัมพันธ์กับวิวพอร์ตหรือไม่


5
หมายเหตุ: ดูคำตอบของ @Igor G ...
Carl Smith

3
สำหรับ DA คุณควรตั้งค่าคำตอบของ Igor G เป็นที่ยอมรับจริงๆมันช่วยชีวิต!
Vincent Duprez

คำตอบ:


26

ดูที่ปลั๊กอิน Dimensions โดยเฉพาะscrollTop()/ scrollLeft(). ข้อมูลสามารถพบได้ที่http://api.jquery.com/scrollTop


8
ฉันไม่ต้องการใช้ปลั๊กอินอื่น แต่ $ (window) .scrollTop () คือสิ่งที่ฉันต้องการ! ขอบคุณ!
DA.

16
ตอนนี้ปลั๊กอินขนาดเป็นส่วนหนึ่งของแกน jQuery ปลั๊กอิน ViewPort ยังมีประโยชน์: appelsiini.net/projects/viewport
StriplingWarrior

288

วิธีที่ง่ายที่สุดในการกำหนดขนาดและตำแหน่งขององค์ประกอบคือการโทรของ getBoundingClientRect ()วิธีการ วิธีนี้ส่งคืนตำแหน่งองค์ประกอบในพิกัดวิวพอร์ต คาดว่าไม่มีข้อโต้แย้งและส่งกลับวัตถุที่มีคุณสมบัติซ้ายขวาด้านบนและด้านล่าง คุณสมบัติด้านซ้ายและด้านบนให้พิกัด X และ Y ของมุมบนซ้ายขององค์ประกอบและคุณสมบัติด้านขวาและด้านล่างจะให้พิกัดของมุมล่างขวา

element.getBoundingClientRect(); // Get position in viewport coordinates

รองรับทุกที่


15
มันเหลือเชื่อมากที่วิธีนี้ถูกเพิ่มเข้ามาโดย IE5 ... เมื่อบางอย่างดีก็ดี!
roy riojas

สิ่งนี้ดูเหมือนดีในตอนแรก แต่ไม่ได้คำนึงถึงผู้ใช้ที่ซูมบน Mobile Safari 7
MyNameIsKo

2
ไม่รองรับ firefox ล่าสุดgetBoundingClientRect is not a function
user007

2
@ user007 ฉันยืนยันว่ามันรองรับโดย Firefox ล่าสุด
adriendenat

27
คำตอบที่ดีและเพื่อให้เป็น jquery เพียงแค่ทำสิ่งนี้: $('#myElement')[0].getBoundingClientRect().top(หรือตำแหน่งอื่น ๆ )
Guillaume Arluison

40

ต่อไปนี้เป็นฟังก์ชันสองอย่างในการรับความสูงของหน้าและจำนวนการเลื่อน (x, y) โดยไม่ต้องใช้ปลั๊กอินขนาด (ป่อง):

// getPageScroll() by quirksmode.com
function getPageScroll() {
    var xScroll, yScroll;
    if (self.pageYOffset) {
      yScroll = self.pageYOffset;
      xScroll = self.pageXOffset;
    } else if (document.documentElement && document.documentElement.scrollTop) {
      yScroll = document.documentElement.scrollTop;
      xScroll = document.documentElement.scrollLeft;
    } else if (document.body) {// all other Explorers
      yScroll = document.body.scrollTop;
      xScroll = document.body.scrollLeft;
    }
    return new Array(xScroll,yScroll)
}

// Adapted from getPageSize() by quirksmode.com
function getPageHeight() {
    var windowHeight
    if (self.innerHeight) { // all except Explorer
      windowHeight = self.innerHeight;
    } else if (document.documentElement && document.documentElement.clientHeight) {
      windowHeight = document.documentElement.clientHeight;
    } else if (document.body) { // other Explorers
      windowHeight = document.body.clientHeight;
    }
    return windowHeight
}

นี่เป็นสิ่งที่ยอดเยี่ยม มีประโยชน์มาก.
Jimmy

ด้วยความอยากรู้อยากเห็นทำไมคุณถึงใช้คุณสมบัติ "self" แทนหน้าต่างในกรณีนี้
dkugappi


23

jQuery.offsetจะต้องรวมกับscrollTopและscrollLeftตามที่แสดงในแผนภาพนี้:

การเลื่อนวิวพอร์ตและการชดเชยองค์ประกอบ

การสาธิต:

function getViewportOffset($e) {
  var $window = $(window),
    scrollLeft = $window.scrollLeft(),
    scrollTop = $window.scrollTop(),
    offset = $e.offset(),
    rect1 = { x1: scrollLeft, y1: scrollTop, x2: scrollLeft + $window.width(), y2: scrollTop + $window.height() },
    rect2 = { x1: offset.left, y1: offset.top, x2: offset.left + $e.width(), y2: offset.top + $e.height() };
  return {
    left: offset.left - scrollLeft,
    top: offset.top - scrollTop,
    insideViewport: rect1.x1 < rect2.x2 && rect1.x2 > rect2.x1 && rect1.y1 < rect2.y2 && rect1.y2 > rect2.y1
  };
}
$(window).on("load scroll resize", function() {
  var viewportOffset = getViewportOffset($("#element"));
  $("#log").text("left: " + viewportOffset.left + ", top: " + viewportOffset.top + ", insideViewport: " + viewportOffset.insideViewport);
});
body { margin: 0; padding: 0; width: 1600px; height: 2048px; background-color: #CCCCCC; }
#element { width: 384px; height: 384px; margin-top: 1088px; margin-left: 768px; background-color: #99CCFF; }
#log { position: fixed; left: 0; top: 0; font: medium monospace; background-color: #EEE8AA; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

<!-- scroll right and bottom to locate the blue square -->
<div id="element"></div>
<div id="log"></div>


2
สิ่งนี้ใช้งานได้ดีสำหรับฉัน แต่ฉันใช้สิ่งนี้เพื่อตรวจสอบว่าคำแนะนำเครื่องมือออกนอกขอบเขตหรือไม่ดังนั้นฉันจึงแก้ไขเพื่อรวมค่าด้านล่างและด้านขวา: jsfiddle.net/EY6Rk/21
Jordan

นี่คือคำตอบที่ถูกต้องไม่ว่าในกรณีใด ๆ อื่น ๆ ทั้งหมดมีปัญหาขึ้นอยู่กับการกำหนดค่าเดลต้าเมาส์ / เลื่อนเบราว์เซอร์ตำแหน่ง obj ฯลฯ
Pedro Ferreira

2

นี่คือฟังก์ชันที่คำนวณตำแหน่งปัจจุบันขององค์ประกอบภายในวิวพอร์ต:

/**
 * Calculates the position of a given element within the viewport
 *
 * @param {string} obj jQuery object of the dom element to be monitored
 * @return {array} An array containing both X and Y positions as a number
 * ranging from 0 (under/right of viewport) to 1 (above/left of viewport)
 */
function visibility(obj) {
    var winw = jQuery(window).width(), winh = jQuery(window).height(),
        elw = obj.width(), elh = obj.height(),
        o = obj[0].getBoundingClientRect(),
        x1 = o.left - winw, x2 = o.left + elw,
        y1 = o.top - winh, y2 = o.top + elh;

    return [
        Math.max(0, Math.min((0 - x1) / (x2 - x1), 1)),
        Math.max(0, Math.min((0 - y1) / (y2 - y1), 1))
    ];
}

ค่าที่ส่งคืนคำนวณดังนี้:

การใช้งาน:

visibility($('#example'));  // returns [0.3742887830933581, 0.6103752759381899]

การสาธิต:

function visibility(obj) {var winw = jQuery(window).width(),winh = jQuery(window).height(),elw = obj.width(),
    elh = obj.height(), o = obj[0].getBoundingClientRect(),x1 = o.left - winw, x2 = o.left + elw, y1 = o.top - winh, y2 = o.top + elh; return [Math.max(0, Math.min((0 - x1) / (x2 - x1), 1)),Math.max(0, Math.min((0 - y1) / (y2 - y1), 1))];
}
setInterval(function() {
  res = visibility($('#block'));
  $('#x').text(Math.round(res[0] * 100) + '%');
  $('#y').text(Math.round(res[1] * 100) + '%');
}, 100);
#block { width: 100px; height: 100px; border: 1px solid red; background: yellow; top: 50%; left: 50%; position: relative;
} #container { background: #EFF0F1; height: 950px; width: 1800px; margin-top: -40%; margin-left: -40%; overflow: scroll; position: relative;
} #res { position: fixed; top: 0; z-index: 2; font-family: Verdana; background: #c0c0c0; line-height: .1em; padding: 0 .5em; font-size: 12px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="res">
  <p>X: <span id="x"></span></p>
  <p>Y: <span id="y"></span></p>
</div>
<div id="container"><div id="block"></div></div>


0

ฉันพบว่าคำตอบของ cballou ไม่สามารถใช้งานได้ใน Firefox อีกต่อไปในเดือนมกราคม 2014 โดยเฉพาะอย่างยิ่งif (self.pageYOffset)ไม่ได้เรียกใช้หากไคลเอนต์เลื่อนไปทางขวา แต่ไม่ลง - เนื่องจาก0เป็นตัวเลขที่ผิดพลาด สิ่งนี้ตรวจไม่พบมาระยะหนึ่งแล้วเนื่องจาก Firefox รองรับdocument.body.scrollLeft/ Topแต่สิ่งนี้ใช้ไม่ได้สำหรับฉันอีกต่อไป (บน Firefox 26.0)

นี่คือวิธีแก้ไขของฉัน:

var getPageScroll = function(document_el, window_el) {
  var xScroll = 0, yScroll = 0;
  if (window_el.pageYOffset !== undefined) {
    yScroll = window_el.pageYOffset;
    xScroll = window_el.pageXOffset;
  } else if (document_el.documentElement !== undefined && document_el.documentElement.scrollTop) {
    yScroll = document_el.documentElement.scrollTop;
    xScroll = document_el.documentElement.scrollLeft;
  } else if (document_el.body !== undefined) {// all other Explorers
    yScroll = document_el.body.scrollTop;
    xScroll = document_el.body.scrollLeft;
  }
  return [xScroll,yScroll];
};

ทดสอบและทำงานใน FF26, Chrome 31, IE11 เกือบจะใช้ได้กับเวอร์ชันเก่าของพวกเขาทั้งหมด

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