Sử dụng jquery để nhận vị trí của phần tử so với khung nhìn


117

Cách thích hợp để có được vị trí của một phần tử trên trang so với chế độ xem (thay vì tài liệu). jQuery.offsetchức năng có vẻ hứa hẹn:

Lấy tọa độ hiện tại của phần tử đầu tiên hoặc đặt tọa độ của mọi phần tử, trong tập hợp các phần tử đã so khớp, liên quan đến tài liệu.

Nhưng đó là liên quan đến tài liệu. Có phương pháp tương đương nào trả về hiệu số so với khung nhìn không?


5
LƯU Ý: Xem câu trả lời của @Igor G ...
Carl Smith

3
Đối với DA, bạn thực sự nên đặt câu trả lời của Igor G là được chấp nhận, đó là một món đồ tiết kiệm!
Vincent Duprez

Câu trả lời:



287

Cách dễ nhất để xác định kích thước và vị trí của một phần tử là gọi phương thức getBoundsClientRect () của nó . Phương thức này trả về vị trí phần tử trong tọa độ khung nhìn. Nó mong đợi không có đối số và trả về một đối tượng có các thuộc tính trái, phải, trêndưới . Thuộc tính left và top cung cấp tọa độ X và Y của góc trên bên trái của phần tử và thuộc tính right và bottom cung cấp tọa độ của góc dưới bên phải.

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

Được hỗ trợ ở mọi nơi.


15
Thật không thể tin được phương pháp này đã được IE5 thêm vào ... khi một cái gì đó tốt, là tốt!
roy riojas

Điều này dường như rất tốt lúc đầu nhưng nó không chiếm một zoom người dùng trên di động Safari 7.
MyNameIsKo

2
Không được hỗ trợ bởi mới nhất firefoxgetBoundingClientRect is not a function
user007

2
@ user007 Tôi xác nhận rằng nó được firefox mới nhất hỗ trợ.
adriendenat

26
Great câu trả lời, và để làm cho nó jQuery đơn giản làm theo cách này: $('#myElement')[0].getBoundingClientRect().top(hoặc bất kỳ vị trí khác)
Guillaume Arluison

40

Dưới đây là hai chức năng để lấy chiều cao trang và số lượng cuộn (x, y) mà không cần sử dụng plugin kích thước (phình to):

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

Điều này là tuyệt vời. Rất hữu ích.
Jimmy

Vì tò mò, tại sao bạn lại sử dụng thuộc tính "self" thay vì window trong trường hợp này?
dkugappi


23

jQuery.offsetcần được kết hợp với scrollTopscrollLeftnhư thể hiện trong sơ đồ này:

cuộn khung nhìn và phần tử bù đắp

Bản giới thiệu:

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
này làm việc rất lớn đối với tôi, nhưng tôi đã sử dụng này để xác định xem một tooltip sẽ out-of-bounds, vì vậy tôi đã sửa đổi để bao gồm các giá trị dưới và bên phải: jsfiddle.net/EY6Rk/21
Jordan

Đây là câu trả lời hoàn toàn chính xác, trong mọi trường hợp. Tất cả những thứ khác đều có vấn đề tùy thuộc vào cấu hình chuột / cuộn delta, trình duyệt, vị trí đối tượng, v.v.
Pedro Ferreira,

2

Đây là một hàm tính toán vị trí hiện tại của một phần tử trong khung nhìn:

/**
 * 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))
    ];
}

Các giá trị trả về được tính như sau:

Sử dụng:

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

Bản giới thiệu:

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

Tôi thấy rằng câu trả lời của cballou đã không còn hoạt động trong Firefox kể từ tháng 1 năm 2014. Cụ thể, if (self.pageYOffset)không kích hoạt nếu khách hàng đã cuộn sang phải, nhưng không xuống - vì 0là một số sai. Điều này đã không được phát hiện trong một thời gian vì Firefox hỗ trợ document.body.scrollLeft/ Top, nhưng điều này không còn hoạt động đối với tôi (trên Firefox 26.0).

Đây là giải pháp đã sửa đổi của tôi:

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

Đã thử nghiệm và hoạt động trong FF26, Chrome 31, IE11. Hầu như chắc chắn hoạt động trên các phiên bản cũ hơn của tất cả chúng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.