【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
有没有一种有效的方法来判断DOM元素(在HTML文档中)当前是否可见(显示在视口中 )?
(问题是指Firefox)
#1楼
请参阅使用getBoundingClientRect的边缘源。 就像是:
function inViewport (el) {
var r, html;
if ( !el || 1 !== el.nodeType ) { return false; }
html = document.documentElement;
r = el.getBoundingClientRect();
return ( !!r
&& r.bottom >= 0
&& r.right >= 0
&& r.top <= html.clientHeight
&& r.left <= html.clientWidth
);
}
如果元素的任何部分在视口中,则返回true
。
#2楼
更新:时间在前进,我们的浏览器也在前进。 不再推荐使用此技术,如果不需要支持IE <7,则应使用下面的@Dan解决方案( https://stackoverflow.com/a/7557433/5628 )。
原始解决方案(现已过时):
这将检查该元素在当前视口中是否完全可见:
function elementInViewport(el) {
var top = el.offsetTop;
var left = el.offsetLeft;
var width = el.offsetWidth;
var height = el.offsetHeight;
while(el.offsetParent) {
el = el.offsetParent;
top += el.offsetTop;
left += el.offsetLeft;
}
return (
top >= window.pageYOffset &&
left >= window.pageXOffset &&
(top + height) <= (window.pageYOffset + window.innerHeight) &&
(left + width) <= (window.pageXOffset + window.innerWidth)
);
}
您可以简单地对此进行修改,以确定元素的任何部分在视口中是否可见:
function elementInViewport2(el) {
var top = el.offsetTop;
var left = el.offsetLeft;
var width = el.offsetWidth;
var height = el.offsetHeight;
while(el.offsetParent) {
el = el.offsetParent;
top += el.offsetTop;
left += el.offsetLeft;
}
return (
top < (window.pageYOffset + window.innerHeight) &&
left < (window.pageXOffset + window.innerWidth) &&
(top + height) > window.pageYOffset &&
(left + width) > window.pageXOffset
);
}
#3楼
更好的解决方案:
function getViewportSize(w) {
var w = w || window;
if(w.innerWidth != null) return {w:w.innerWidth, h:w.innerHeight};
var d = w.document;
if (document.compatMode == "CSS1Compat") {
return {
w: d.documentElement.clientWidth,
h: d.documentElement.clientHeight
};
}
return { w: d.body.clientWidth, h: d.body.clientWidth };
}
function isViewportVisible(e) {
var box = e.getBoundingClientRect();
var height = box.height || (box.bottom - box.top);
var width = box.width || (box.right - box.left);
var viewport = getViewportSize();
if(!height || !width) return false;
if(box.top > viewport.h || box.bottom < 0) return false;
if(box.right < 0 || box.left > viewport.w) return false;
return true;
}
#4楼
更新资料
在现代浏览器中,您可能想查看Intersection Observer API ,它具有以下优点:
- 比收听滚动事件更好的性能
- 适用于跨网域iframe
- 可以判断一个元素是否正在阻碍/相交
Intersection Observer正在成为完善的标准,并且已在Chrome 51 +,Edge 15+和Firefox 55+中得到支持,并且正在为Safari开发。 还有一个polyfill可用。
先前的答案
Dan提供的答案存在一些问题,可能使它不适用于某些情况。 他在底部的答案中指出了其中一些问题,即他的代码将对以下元素产生误报:
- 被正在测试的元素前面的另一个元素隐藏
- 在父元素或祖先元素的可见区域之外
- 使用CSS
clip
属性隐藏的元素或其子元素
解决方案: isElementVisible()
这是这些问题的解决方案,下面是测试结果,并对代码的某些部分进行了说明。
function isElementVisible(el) {
var rect = el.getBoundingClientRect(),
vWidth = window.innerWidth || doc.documentElement.clientWidth,
vHeight = window.innerHeight || doc.documentElement.clientHeight,
efp = function (x, y) { return document.elementFromPoint(x, y) };
// Return false if it's not in the viewport
if (rect.right < 0 || rect.bottom < 0
|| rect.left > vWidth || rect.top > vHeight)
return false;
// Return true if any of its four corners are visible
return (
el.contains(efp(rect.left, rect.top))
|| el.contains(efp(rect.right, rect.top))
|| el.contains(efp(rect.right, rect.bottom))
|| el.contains(efp(rect.left, rect.bottom))
);
}
通过测试: http : //jsfiddle.net/AndyE/cAY8c/
结果:
附加条款
但是,此方法并非没有其自身的局限性。 例如,即使在前面的元素实际上没有隐藏其任何部分的情况下,使用比同一位置的另一个元素更低的z-index测试的元素也将被标识为隐藏。 不过,这种方法在某些情况下仍有其用处,但Dan的解决方案却无法解决。
element.getBoundingClientRect()
和document.elementFromPoint()
都是CSSOM工作草案规范的一部分,并且至少在IE 6和更高版本以及大多数台式机浏览器中都得到了长期支持(尽管并非完全如此)。 有关更多信息,请参见这些功能的Quirksmode 。
contains()
用于查看document.elementFromPoint()
返回的元素是否是我们正在测试可见性的元素的子节点。 如果返回的元素是同一元素,则它也返回true。 这只会使检查更可靠。 所有主要浏览器均支持该功能,Firefox 9.0是它们最后添加的浏览器。 要获得较早的Firefox支持,请查看此答案的历史记录。
如果要在元素周围测试更多点的可见性(例如,确保元素覆盖率不超过50%),则无需花费太多时间来调整答案的最后一部分。 但是请注意,如果检查每个像素以确保其100%可见,这可能会非常慢。
#5楼
我尝试了Dan的答案, 但是用于确定范围的代数意味着该元素必须既≤视口大小,又必须完全在视口内才能得到true
,很容易导致假阴性。 如果要确定某个元素是否完全在视口中,则ryanve的答案很接近,但是要测试的元素应与该视口重叠,因此请尝试以下操作:
function isElementInViewport(el) {
var rect = el.getBoundingClientRect();
return rect.bottom > 0 &&
rect.right > 0 &&
rect.left < (window.innerWidth || document.documentElement.clientWidth) /* or $(window).width() */ &&
rect.top < (window.innerHeight || document.documentElement.clientHeight) /* or $(window).height() */;
}
来源:oschina
链接:https://my.oschina.net/u/3797416/blog/3143693