是否有一种有效的方法来判断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;
}
其他回答
这里所有的答案都是确定元素是否完全包含在视口中,而不仅仅是以某种方式可见。例如,如果在视图的底部只有图像的一半可见,这里的解决方案将失败,考虑到“外部”。
我有一个用例,我正在通过IntersectionObserver进行惰性加载,但由于弹出过程中发生的动画,我不想观察任何已经在页面加载上交叉的图像。为此,我使用了以下代码:
const bounding = el.getBoundingClientRect();
const isVisible = (0 < bounding.top && bounding.top < (window.innerHeight || document.documentElement.clientHeight)) ||
(0 < bounding.bottom && bounding.bottom < (window.innerHeight || document.documentElement.clientHeight));
这基本上是检查顶部或底部边界是否在视口中独立。另一端可能在外面,但只要一端在里面,它至少是部分“可见”的。
对于类似的挑战,我非常喜欢这个要点,它为scrollIntoViewIfNeeded()暴露了一个填充。
所有必要的功夫都需要回答这个问题:
var parent = this.parentNode,
parentComputedStyle = window.getComputedStyle(parent, null),
parentBorderTopWidth = parseInt(parentComputedStyle.getPropertyValue('border-top-width')),
parentBorderLeftWidth = parseInt(parentComputedStyle.getPropertyValue('border-left-width')),
overTop = this.offsetTop - parent.offsetTop < parent.scrollTop,
overBottom = (this.offsetTop - parent.offsetTop + this.clientHeight - parentBorderTopWidth) > (parent.scrollTop + parent.clientHeight),
overLeft = this.offsetLeft - parent.offsetLeft < parent.scrollLeft,
overRight = (this.offsetLeft - parent.offsetLeft + this.clientWidth - parentBorderLeftWidth) > (parent.scrollLeft + parent.clientWidth),
alignWithTop = overTop && !overBottom;
这指的是你想知道的元素,例如,overTop或overBottom -你只需要得到漂移…
在Android上放大谷歌Chrome浏览器时,最被接受的答案是不工作的。结合Dan的回答,要考虑Android上的Chrome,必须使用visualViewport。下面的例子只考虑了垂直检查,并使用jQuery来计算窗口高度:
var Rect = YOUR_ELEMENT.getBoundingClientRect();
var ElTop = Rect.top, ElBottom = Rect.bottom;
var WindowHeight = $(window).height();
if(window.visualViewport) {
ElTop -= window.visualViewport.offsetTop;
ElBottom -= window.visualViewport.offsetTop;
WindowHeight = window.visualViewport.height;
}
var WithinScreen = (ElTop >= 0 && ElBottom <= WindowHeight);
我们现在有一个原生javascript交集观察者API 从中我们可以检测元素,无论它们是否在视口中。
这里有一个例子
const el = document.querySelector('#el') const observer = new window.IntersectionObserver(([entry]) => { if (entry. isintersection) { console.log(输入) 返回 } console.log(离开) }, { 根:空, 阈值:0.1,//设置偏移量0.1表示如果元素在视口中至少占10%,则触发 }) observer.observe (el); 身体{ 身高:300 vh; } # el { margin-top: 100 vh; } <div id="el">这是元素</div>
我有同样的问题,并通过使用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.');
}
};