是否有一种有效的方法来判断DOM元素(在HTML文档中)当前是否可见(出现在视口中)?
(这个问题指的是Firefox。)
是否有一种有效的方法来判断DOM元素(在HTML文档中)当前是否可见(出现在视口中)?
(这个问题指的是Firefox。)
当前回答
/**
* Returns Element placement information in Viewport
* @link https://stackoverflow.com/a/70476497/2453148
*
* @typedef {object} ViewportInfo - Whether the element is…
* @property {boolean} isInViewport - fully or partially in the viewport
* @property {boolean} isPartiallyInViewport - partially in the viewport
* @property {boolean} isInsideViewport - fully inside viewport
* @property {boolean} isAroundViewport - completely covers the viewport
* @property {boolean} isOnEdge - intersects the edge of viewport
* @property {boolean} isOnTopEdge - intersects the top edge
* @property {boolean} isOnRightEdge - intersects the right edge
* @property {boolean} isOnBottomEdge - is intersects the bottom edge
* @property {boolean} isOnLeftEdge - is intersects the left edge
*
* @param el Element
* @return {Object} ViewportInfo
*/
function getElementViewportInfo(el) {
let result = {};
let rect = el.getBoundingClientRect();
let windowHeight = window.innerHeight || document.documentElement.clientHeight;
let windowWidth = window.innerWidth || document.documentElement.clientWidth;
let insideX = rect.left >= 0 && rect.left + rect.width <= windowWidth;
let insideY = rect.top >= 0 && rect.top + rect.height <= windowHeight;
result.isInsideViewport = insideX && insideY;
let aroundX = rect.left < 0 && rect.left + rect.width > windowWidth;
let aroundY = rect.top < 0 && rect.top + rect.height > windowHeight;
result.isAroundViewport = aroundX && aroundY;
let onTop = rect.top < 0 && rect.top + rect.height > 0;
let onRight = rect.left < windowWidth && rect.left + rect.width > windowWidth;
let onLeft = rect.left < 0 && rect.left + rect.width > 0;
let onBottom = rect.top < windowHeight && rect.top + rect.height > windowHeight;
let onY = insideY || aroundY || onTop || onBottom;
let onX = insideX || aroundX || onLeft || onRight;
result.isOnTopEdge = onTop && onX;
result.isOnRightEdge = onRight && onY;
result.isOnBottomEdge = onBottom && onX;
result.isOnLeftEdge = onLeft && onY;
result.isOnEdge = result.isOnLeftEdge || result.isOnRightEdge ||
result.isOnTopEdge || result.isOnBottomEdge;
let isInX =
insideX || aroundX || result.isOnLeftEdge || result.isOnRightEdge;
let isInY =
insideY || aroundY || result.isOnTopEdge || result.isOnBottomEdge;
result.isInViewport = isInX && isInY;
result.isPartiallyInViewport =
result.isInViewport && result.isOnEdge;
return result;
}
其他回答
在我看来,非常简单:
function isVisible(elem) {
var coords = elem.getBoundingClientRect();
return Math.abs(coords.top) <= coords.height;
}
我在这里遇到的所有答案都只是检查元素是否位于当前视口中。但这并不意味着它是可见的。 如果给定的元素在一个包含满溢内容的div中,并且它被滚动到视图之外,该怎么办?
要解决这个问题,您必须检查元素是否被所有父元素所包含。 我的解决方案就是这样:
它还允许您指定多少元素必须是可见的。
Element.prototype.isVisible = function(percentX, percentY){
var tolerance = 0.01; //needed because the rects returned by getBoundingClientRect provide the position up to 10 decimals
if(percentX == null){
percentX = 100;
}
if(percentY == null){
percentY = 100;
}
var elementRect = this.getBoundingClientRect();
var parentRects = [];
var element = this;
while(element.parentElement != null){
parentRects.push(element.parentElement.getBoundingClientRect());
element = element.parentElement;
}
var visibleInAllParents = parentRects.every(function(parentRect){
var visiblePixelX = Math.min(elementRect.right, parentRect.right) - Math.max(elementRect.left, parentRect.left);
var visiblePixelY = Math.min(elementRect.bottom, parentRect.bottom) - Math.max(elementRect.top, parentRect.top);
var visiblePercentageX = visiblePixelX / elementRect.width * 100;
var visiblePercentageY = visiblePixelY / elementRect.height * 100;
return visiblePercentageX + tolerance > percentX && visiblePercentageY + tolerance > percentY;
});
return visibleInAllParents;
};
这个解决方案忽略了元素可能由于其他因素而不可见的事实,比如不透明度:0。
我已经在Chrome和Internet Explorer 11中测试了这个解决方案。
查看verge的源代码,它使用getBoundingClientRect。这就像:
function inViewport (element) {
if (!element) return false;
if (1 !== element.nodeType) return false;
var html = document.documentElement;
var rect = element.getBoundingClientRect();
return !!rect &&
rect.bottom >= 0 &&
rect.right >= 0 &&
rect.left <= html.clientWidth &&
rect.top <= html.clientHeight;
}
如果元素的任何部分在视口中,则返回true。
我有同样的问题,并通过使用getBoundingClientRect()来解决。
这段代码完全是“通用的”,只需要写一次就可以工作(你不需要为你想知道的每个元素都写出来)。
这段代码只检查它在视口中是否垂直,而不是水平。在本例中,变量(array)'elements'保存了所有你要检查的垂直在视口中的元素,所以在任何地方抓取任何你想要的元素并将它们存储在那里。
for循环遍历每个元素并检查它是否垂直地位于视口中。这段代码在用户每次滚动时执行!如果getBoudingClientRect()。Top小于viewport的3/4(元素在viewport中的四分之一),它注册为“在viewport中”。
因为代码是通用的,你会想知道“哪个”元素在视口中。要找出这一点,可以通过自定义属性、节点名、id、类名等确定。
这是我的代码(如果它不起作用,请告诉我;它已在Internet Explorer 11、Firefox 40.0.3、Chrome Version 45.0.2454.85 m、Opera 31.0.1889.174和Edge with Windows 10(还没有Safari)上测试……
// Scrolling handlers...
window.onscroll = function(){
var elements = document.getElementById('whatever').getElementsByClassName('whatever');
for(var i = 0; i != elements.length; i++)
{
if(elements[i].getBoundingClientRect().top <= window.innerHeight*0.75 &&
elements[i].getBoundingClientRect().top > 0)
{
console.log(elements[i].nodeName + ' ' +
elements[i].className + ' ' +
elements[i].id +
' is in the viewport; proceed with whatever code you want to do here.');
}
};
我使用这个函数(它只检查y是否在屏幕上,因为大多数时候x是不需要的)
function elementInViewport(el) {
var elinfo = {
"top":el.offsetTop,
"height":el.offsetHeight,
};
if (elinfo.top + elinfo.height < window.pageYOffset || elinfo.top > window.pageYOffset + window.innerHeight) {
return false;
} else {
return true;
}
}