使用 jQuery 获取 div 的可见高度

我需要检索可滚动区域内 div 的可见高度。我认为自己使用 jQuery 是相当得体的,但这完全把我抛弃了。

假设我在一个黑色包装内有一个红色的 div:

在上图中,jQuery 函数将返回248,即 div 的可见部分。

如上图所示,一旦用户滚动到 div 顶部,它将报告296。

现在,一旦用户滚动过 div,它将再次报告248。

显然,我的数字不会像这个演示中的那样一致和清晰,否则我只能硬编码这些数字。

我有个想法:

  • 得到窗户的高度
  • 得到 div 的高度
  • 从窗口顶部获取 div 的初始偏移量
  • 获取用户滚动时的偏移量。
    • 如果偏移量为正,则表示 div 的顶部仍然可见。
    • 如果是负的,那么 div 的顶部被窗口遮挡了。此时,div 可以占据窗口的整个高度,也可以显示 div 的底部
    • 如果显示了 div 的底部,那么计算出它与窗口底部之间的间隙。

看起来很简单,但我就是想不通。明天早上我再试一次,我想你们这些天才也许能帮上忙。

谢谢!

更新: 这是我自己想出来的,但是看起来下面的一个答案更加优雅,所以我将用它来代替。对于好奇的人,这是我想到的:

$(document).ready(function() {
var windowHeight = $(window).height();
var overviewHeight = $("#overview").height();
var overviewStaticTop = $("#overview").offset().top;
var overviewScrollTop = overviewStaticTop - $(window).scrollTop();
var overviewStaticBottom = overviewStaticTop + $("#overview").height();
var overviewScrollBottom = windowHeight - (overviewStaticBottom - $(window).scrollTop());
var visibleArea;
if ((overviewHeight + overviewScrollTop) < windowHeight) {
// alert("bottom is showing!");
visibleArea = windowHeight - overviewScrollBottom;
// alert(visibleArea);
} else {
if (overviewScrollTop < 0) {
// alert("is full height");
visibleArea = windowHeight;
// alert(visibleArea);
} else {
// alert("top is showing");
visibleArea = windowHeight - overviewScrollTop;
// alert(visibleArea);
}
}
});
70159 次浏览

Here is a quick and dirty concept. It basically compares the offset().top of the element to the top of the window, and the offset().top + height() to the bottom of the window:

function getVisible() {
var $el = $('#foo'),
scrollTop = $(this).scrollTop(),
scrollBot = scrollTop + $(this).height(),
elTop = $el.offset().top,
elBottom = elTop + $el.outerHeight(),
visibleTop = elTop < scrollTop ? scrollTop : elTop,
visibleBottom = elBottom > scrollBot ? scrollBot : elBottom;
$('#notification').text(`Visible height of div: ${visibleBottom - visibleTop}px`);
}


$(window).on('scroll resize', getVisible).trigger('scroll');
html,
body {
margin: 100px 0;
}


#foo {
height: 1000px;
background-color: #C00;
width: 200px;
margin: 0 auto;
}


#notification {
position: fixed;
top: 0;
left: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<div id="foo"></div>
<div id="notification"></div>

The logic can be made more succinct if necessary, I've just declared separate variables for this example to make the calculation as clear as I can.

Calculate the amount of px an element (height) is in viewport

Fiddle demo

This tiny function will return the amount of px an element is visible in the (vertical) Viewport:

function inViewport($el) {
var elH = $el.outerHeight(),
H   = $(window).height(),
r   = $el[0].getBoundingClientRect(), t=r.top, b=r.bottom;
return Math.max(0, t>0? Math.min(elH, H-t) : Math.min(b, H));
}

Use like:

$(window).on("scroll resize", function(){
console.log( inViewport($('#elementID')) ); // n px in viewport
});

that's it.


jQuery .inViewport() Plugin

jsFiddle demo

from the above you can extract the logic and create a plugin like this one:

/**
* inViewport jQuery plugin by Roko C.B.
* http://stackoverflow.com/a/26831113/383904
* Returns a callback function with an argument holding
* the current amount of px an element is visible in viewport
* (The min returned value is 0 (element outside of viewport)
*/
;(function($, win) {
$.fn.inViewport = function(cb) {
return this.each(function(i,el) {
function visPx(){
var elH = $(el).outerHeight(),
H = $(win).height(),
r = el.getBoundingClientRect(), t=r.top, b=r.bottom;
return cb.call(el, Math.max(0, t>0? Math.min(elH, H-t) : Math.min(b, H)));
}
visPx();
$(win).on("resize scroll", visPx);
});
};
}(jQuery, window));

Use like:

$("selector").inViewport(function(px) {
console.log( px ); // `px` represents the amount of visible height
if(px > 0) {
// do this if element enters the viewport // px > 0
}else{
// do that if element exits  the viewport // px = 0
}
}); // Here you can chain other jQuery methods to your selector

your selectors will dynamically listen to window scroll and resize but also return the initial value on DOM ready trough the first callback function argument px.

Here is a version of Rory's approach above, except written to function as a jQuery plugin. It may have more general applicability in that format. Great answer, Rory - thanks!

$.fn.visibleHeight = function() {
var elBottom, elTop, scrollBot, scrollTop, visibleBottom, visibleTop;
scrollTop = $(window).scrollTop();
scrollBot = scrollTop + $(window).height();
elTop = this.offset().top;
elBottom = elTop + this.outerHeight();
visibleTop = elTop < scrollTop ? scrollTop : elTop;
visibleBottom = elBottom > scrollBot ? scrollBot : elBottom;
return visibleBottom - visibleTop
}

Can be called with the following:

$("#myDiv").visibleHeight();

jsFiddle

Here is the improved code for jquery function visibleHeight: $("#myDiv").visibleHeight();

$.fn.visibleHeight = function() {
var elBottom, elTop, scrollBot, scrollTop, visibleBottom, visibleTop, height;
scrollTop = $(window).scrollTop();
scrollBot = scrollTop + $(window).height();
elTop = this.offset().top;
elBottom = elTop + this.outerHeight();
visibleTop = elTop < scrollTop ? scrollTop : elTop;
visibleBottom = elBottom > scrollBot ? scrollBot : elBottom;
height = visibleBottom - visibleTop;
return height > 0 ? height : 0;
}