Hom*_*ith 334 javascript dom
有什么方法可以检查一个元素是否在纯JS(没有jQuery)中可见?
因此,例如,在此页面中:Performance Bikes,如果您将鼠标悬停在Deals(在顶部菜单上),则会出现一个交易窗口,但在开始时它没有显示.它在HTML中,但不可见.
因此,给定一个DOM元素,我该如何检查它是否可见?我试过了:
window.getComputedStyle(my_element)['display']);
Run Code Online (Sandbox Code Playgroud)
但它似乎没有起作用.我想知道应该检查哪些属性.它出现在我的脑海里:
display !== 'none'
visibility !== 'hidden'
Run Code Online (Sandbox Code Playgroud)
还有其他我可能会失踪的人?
Ale*_*exZ 546
根据此MDN文档,元素的offsetParent
属性将null
在通过显示样式属性隐藏它或其任何父项时返回.只需确保元素不固定.如果您position: fixed;
的页面上没有元素,则检查此脚本的脚本可能如下所示:
// Where el is the DOM element you'd like to test for visibility
function isHidden(el) {
return (el.offsetParent === null)
}
Run Code Online (Sandbox Code Playgroud)
另一方面,如果你确实有固定的位置元素可能会在这个搜索中被捕获,你会遗憾地(并且慢慢地)使用它window.getComputedStyle()
.在这种情况下的功能可能是:
// Where el is the DOM element you'd like to test for visibility
function isHidden(el) {
var style = window.getComputedStyle(el);
return (style.display === 'none')
}
Run Code Online (Sandbox Code Playgroud)
选项#2可能稍微简单一些,因为它占据了更多的边缘情况,但我打赌它的速度也很慢,所以如果你不得不多次重复这个操作,最好避免它.
guy*_*abi 93
所有其他解决方案对我来说都打破了某些情况..
看到获胜的答案:
http://plnkr.co/edit/6CSCA2fe4Gqt4jCBP2wu?p=preview
最终,我认为最好的解决方案是$(elem).is(':visible')
- 但是,这不是纯粹的javascript.这是jquery ..
所以我偷看了他们的来源并找到了我想要的东西
jQuery.expr.filters.visible = function( elem ) {
return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );
};
Run Code Online (Sandbox Code Playgroud)
这是来源:https://github.com/jquery/jquery/blob/master/src/css/hiddenVisibleSelectors.js
Mah*_*zad 50
Chrome 105(以及 Edge 和 Opera)和Firefox 106引入了如果元素可见则Element.checkVisibility()
返回,否则返回。true
false
该函数检查使元素不可见的各种因素,包括display:none
、visibility
、content-visibility
和opacity
:
let element = document.getElementById("myIcon");
let isVisible = element.checkVisibility({
checkOpacity: true, // Check CSS opacity property too
checkVisibilityCSS: true // Check CSS visibility property too
});
Run Code Online (Sandbox Code Playgroud)
旁注:checkVisibility()
以前称为isVisible()
. 请参阅此 GitHub 问题。
请参阅checkVisibility()
此处的规范草案。
Oha*_*von 45
如果您对用户可见:
function isVisible(elem) {
if (!(elem instanceof Element)) throw Error('DomUtil: elem is not an element.');
const style = getComputedStyle(elem);
if (style.display === 'none') return false;
if (style.visibility !== 'visible') return false;
if (style.opacity < 0.1) return false;
if (elem.offsetWidth + elem.offsetHeight + elem.getBoundingClientRect().height +
elem.getBoundingClientRect().width === 0) {
return false;
}
const elemCenter = {
x: elem.getBoundingClientRect().left + elem.offsetWidth / 2,
y: elem.getBoundingClientRect().top + elem.offsetHeight / 2
};
if (elemCenter.x < 0) return false;
if (elemCenter.x > (document.documentElement.clientWidth || window.innerWidth)) return false;
if (elemCenter.y < 0) return false;
if (elemCenter.y > (document.documentElement.clientHeight || window.innerHeight)) return false;
let pointContainer = document.elementFromPoint(elemCenter.x, elemCenter.y);
do {
if (pointContainer === elem) return true;
} while (pointContainer = pointContainer.parentNode);
return false;
}
Run Code Online (Sandbox Code Playgroud)
测试(使用mocha术语):
describe.only('visibility', function () {
let div, visible, notVisible, inViewport, leftOfViewport, rightOfViewport, aboveViewport,
belowViewport, notDisplayed, zeroOpacity, zIndex1, zIndex2;
before(() => {
div = document.createElement('div');
document.querySelector('body').appendChild(div);
div.appendChild(visible = document.createElement('div'));
visible.style = 'border: 1px solid black; margin: 5px; display: inline-block;';
visible.textContent = 'visible';
div.appendChild(inViewport = visible.cloneNode(false));
inViewport.textContent = 'inViewport';
div.appendChild(notDisplayed = visible.cloneNode(false));
notDisplayed.style.display = 'none';
notDisplayed.textContent = 'notDisplayed';
div.appendChild(notVisible = visible.cloneNode(false));
notVisible.style.visibility = 'hidden';
notVisible.textContent = 'notVisible';
div.appendChild(leftOfViewport = visible.cloneNode(false));
leftOfViewport.style.position = 'absolute';
leftOfViewport.style.right = '100000px';
leftOfViewport.textContent = 'leftOfViewport';
div.appendChild(rightOfViewport = leftOfViewport.cloneNode(false));
rightOfViewport.style.right = '0';
rightOfViewport.style.left = '100000px';
rightOfViewport.textContent = 'rightOfViewport';
div.appendChild(aboveViewport = leftOfViewport.cloneNode(false));
aboveViewport.style.right = '0';
aboveViewport.style.bottom = '100000px';
aboveViewport.textContent = 'aboveViewport';
div.appendChild(belowViewport = leftOfViewport.cloneNode(false));
belowViewport.style.right = '0';
belowViewport.style.top = '100000px';
belowViewport.textContent = 'belowViewport';
div.appendChild(zeroOpacity = visible.cloneNode(false));
zeroOpacity.textContent = 'zeroOpacity';
zeroOpacity.style.opacity = '0';
div.appendChild(zIndex1 = visible.cloneNode(false));
zIndex1.textContent = 'zIndex1';
zIndex1.style.position = 'absolute';
zIndex1.style.left = zIndex1.style.top = zIndex1.style.width = zIndex1.style.height = '100px';
zIndex1.style.zIndex = '1';
div.appendChild(zIndex2 = zIndex1.cloneNode(false));
zIndex2.textContent = 'zIndex2';
zIndex2.style.left = zIndex2.style.top = '90px';
zIndex2.style.width = zIndex2.style.height = '120px';
zIndex2.style.backgroundColor = 'red';
zIndex2.style.zIndex = '2';
});
after(() => {
div.parentNode.removeChild(div);
});
it('isVisible = true', () => {
expect(isVisible(div)).to.be.true;
expect(isVisible(visible)).to.be.true;
expect(isVisible(inViewport)).to.be.true;
expect(isVisible(zIndex2)).to.be.true;
});
it('isVisible = false', () => {
expect(isVisible(notDisplayed)).to.be.false;
expect(isVisible(notVisible)).to.be.false;
expect(isVisible(document.createElement('div'))).to.be.false;
expect(isVisible(zIndex1)).to.be.false;
expect(isVisible(zeroOpacity)).to.be.false;
expect(isVisible(leftOfViewport)).to.be.false;
expect(isVisible(rightOfViewport)).to.be.false;
expect(isVisible(aboveViewport)).to.be.false;
expect(isVisible(belowViewport)).to.be.false;
});
});
Run Code Online (Sandbox Code Playgroud)
Ash*_*nto 36
这可能有所帮助: 通过将元素放置在最左边的位置来隐藏元素,然后检查offsetLeft属性.如果你想使用jQuery,你可以简单地检查:visible选择器并获得元素的可见性状态.
HTML:
<div id="myDiv">Hello</div>
Run Code Online (Sandbox Code Playgroud)
CSS:
<!-- for javaScript-->
#myDiv{
position:absolute;
left : -2000px;
}
<!-- for jQuery -->
#myDiv{
visibility:hidden;
}
Run Code Online (Sandbox Code Playgroud)
javaScript:
var myStyle = document.getElementById("myDiv").offsetLeft;
if(myStyle < 0){
alert("Div is hidden!!");
}
Run Code Online (Sandbox Code Playgroud)
jQuery:
if( $("#MyElement").is(":visible") == true )
{
alert("Div is hidden!!");
}
Run Code Online (Sandbox Code Playgroud)
Mac*_*cio 34
根据MDN 文档,交互观察者异步观察目标元素与祖先元素或顶级文档视口的交集的变化。这意味着每次元素与视口相交时,交互观察者都会触发。
截至 2021 年,当前除 IE 之外的所有浏览器都支持交集观察器。
const el = document.getElementById("your-target-element");
const observer = new IntersectionObserver((entries) => {
if(entries[0].isIntersecting){
// el is visible
} else {
// el is not visible
}
});
observer.observe(el); // Asynchronous call
Run Code Online (Sandbox Code Playgroud)
该处理程序将在最初创建时触发。然后每当它变得稍微可见或完全不可见时它就会触发。当某个元素在视口中实际不可见时,该元素被视为不可见。因此,如果向下滚动并且元素离开屏幕,则观察者将触发并且// el is not visible
代码将被触发 - 即使元素仍然“显示”(即没有display:none
or visibility:hidden
)。重要的是元素中是否有任何像素在视口中实际可见。
Yva*_*van 29
使用与jQuery相同的代码:
jQuery.expr.pseudos.visible = function( elem ) {
return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );
};
Run Code Online (Sandbox Code Playgroud)
所以,在一个函数中:
function isVisible(e) {
return !!( e.offsetWidth || e.offsetHeight || e.getClientRects().length );
}
Run Code Online (Sandbox Code Playgroud)
就像我的Win/IE10,Linux/Firefox.45,Linux/Chrome.52中的魅力......
非常感谢没有jQuery的jQuery!
eli*_*z82 24
接受的答案对我不起作用。
该(elem.offsetParent !== null)
方法在 Firefox 中工作正常,但在 Chrome 中无效。在 Chrome 中,如果在页面中可见,即使元素position: fixed
也会offsetParent
返回null
。
用户 Phrogz 对具有不同属性的元素进行了大型测试(2,304 个 div)以演示该问题。/sf/answers/814776511/。使用多个浏览器运行它以查看差异。
演示:
//different results in Chrome and Firefox
console.log(document.querySelector('#hidden1').offsetParent); //null Chrome & Firefox
console.log(document.querySelector('#fixed1').offsetParent); //null in Chrome, not null in Firefox
Run Code Online (Sandbox Code Playgroud)
<div id="hidden1" style="display:none;"></div>
<div id="fixed1" style="position:fixed;"></div>
Run Code Online (Sandbox Code Playgroud)
该(getComputedStyle(elem).display !== 'none')
不起作用,因为该元素可以是无形的,因为父母中的一方显示属性设置为无,getComputedStyle
将不会赶上。
演示:
var child1 = document.querySelector('#child1');
console.log(getComputedStyle(child1).display);
//child will show "block" instead of "none"
Run Code Online (Sandbox Code Playgroud)
<div id="parent1" style="display:none;">
<div id="child1" style="display:block"></div>
</div>
Run Code Online (Sandbox Code Playgroud)
的(elem.clientHeight !== 0)
。此方法不受position: fixed
并检查元素父项是否不可见。但是它在没有 css 布局的简单元素方面存在问题,请在此处查看更多信息
演示:
console.log(document.querySelector('#div1').clientHeight); //not zero
console.log(document.querySelector('#span1').clientHeight); //zero
Run Code Online (Sandbox Code Playgroud)
<div id="div1">test1 div</div>
<span id="span1">test2 span</span>
Run Code Online (Sandbox Code Playgroud)
的(elem.getClientRects().length !== 0)
可能似乎解决了以前的3种方法的问题。但是,使用 CSS 技巧(除此之外display: none
)隐藏在页面中的元素存在问题。
演示
console.log(document.querySelector('#notvisible1').getClientRects().length);
console.log(document.querySelector('#notvisible1').clientHeight);
console.log(document.querySelector('#notvisible2').getClientRects().length);
console.log(document.querySelector('#notvisible2').clientHeight);
console.log(document.querySelector('#notvisible3').getClientRects().length);
console.log(document.querySelector('#notvisible3').clientHeight);
Run Code Online (Sandbox Code Playgroud)
<div id="notvisible1" style="height:0; overflow:hidden; background-color:red;">not visible 1</div>
<div id="notvisible2" style="visibility:hidden; background-color:yellow;">not visible 2</div>
<div id="notvisible3" style="opacity:0; background-color:blue;">not visible 3</div>
Run Code Online (Sandbox Code Playgroud)
所以我向你展示的是,没有一种方法是完美的。要进行适当的可见性检查,您必须结合使用最后 3 种方法。
Mat*_*hew 14
结合以上几个答案:
function isVisible (ele) {
var style = window.getComputedStyle(ele);
return style.width !== "0" &&
style.height !== "0" &&
style.opacity !== "0" &&
style.display!=='none' &&
style.visibility!== 'hidden';
}
Run Code Online (Sandbox Code Playgroud)
就像AlexZ所说的那样,如果你更具体地了解你正在寻找什么,这可能比你的其他一些选择要慢,但这应该抓住隐藏元素的所有主要方式.
但是,它还取决于对您而言可见的重要因素.例如,div的高度可以设置为0px,但内容仍然可见,具体取决于溢出属性.或者div的内容可以与背景颜色相同,因此用户看不到它,但仍然在页面上呈现.或者div可以移出屏幕或隐藏在其他div之后,或者它的内容可能是不可见的但边框仍然可见.在某种程度上,"可见"是一个主观的术语.
如果element是常规可见的(display:block和visibillity:visible),但是某些父容器是隐藏的,那么我们可以使用clientWidth和clientHeight进行检查.
function isVisible (ele) {
return ele.clientWidth !== 0 &&
ele.clientHeight !== 0 &&
ele.style.opacity !== 0 &&
ele.style.visibility !== 'hidden';
}
Run Code Online (Sandbox Code Playgroud)
与AlexZ的getComputedStyle()解决方案相比,我有一个更高效的解决方案,当一个人拥有位置'固定'元素时,如果有人愿意忽略一些边缘情况(检查注释):
function isVisible(el) {
/* offsetParent would be null if display 'none' is set.
However Chrome, IE and MS Edge returns offsetParent as null for elements
with CSS position 'fixed'. So check whether the dimensions are zero.
This check would be inaccurate if position is 'fixed' AND dimensions were
intentionally set to zero. But..it is good enough for most cases.*/
if (!el.offsetParent && el.offsetWidth === 0 && el.offsetHeight === 0) {
return false;
}
return true;
}
Run Code Online (Sandbox Code Playgroud)
旁注:严格来说,需要首先定义"可见性".在我的情况下,我正在考虑一个元素可见,只要我可以运行所有DOM方法/属性没有问题(即使不透明度为0或CSS可见性属性是'隐藏'等).
仅供参考,应注意的是getBoundingClientRect()
在某些情况下可以工作。
例如,使用简单的检查元素是否隐藏的方法display: none
可能如下所示:
var box = element.getBoundingClientRect();
var visible = box.width && box.height;
Run Code Online (Sandbox Code Playgroud)
这也很方便,因为它还涵盖了零宽度、零高度和position: fixed
大小写。但是,它不应报告用opacity: 0
或隐藏的元素visibility: hidden
(但两者都不会offsetParent
)。
所以我发现的是最可行的方法:
function visible(elm) {
if(!elm.offsetHeight && !elm.offsetWidth) { return false; }
if(getComputedStyle(elm).visibility === 'hidden') { return false; }
return true;
}
Run Code Online (Sandbox Code Playgroud)
这是基于以下事实:
display: none
元素(甚至是嵌套的)没有宽度和高度。visiblity
是hidden
即使对于嵌套元素。所以不需要offsetParent
在 DOM 树中测试或循环来测试哪个父级有visibility: hidden
. 即使在 IE 9 中,这也应该有效。
您可能会争论opacity: 0
折叠元素(有宽度但没有高度 - 反之亦然)是否真的不可见。但话又说回来,他们不是每说隐藏。
如果我们只是收集检测能见度的基本方法,那么我不要忘记:
opacity > 0.01; // probably more like .1 to actually be visible, but YMMV
Run Code Online (Sandbox Code Playgroud)
至于如何获取属性:
element.getAttribute(attributename);
Run Code Online (Sandbox Code Playgroud)
所以,在你的例子中:
document.getElementById('snDealsPanel').getAttribute('visibility');
Run Code Online (Sandbox Code Playgroud)
但是,哇?它在这里不起作用.仔细观察,您会发现可见性不是作为元素的属性更新,而是使用style
属性.这是尝试做你正在做的事情的许多问题之一.其中:你无法保证在元素中实际可以看到的东西,只是因为它的可见性,显示和不透明度都具有正确的值.它仍然可能缺乏内容,或者可能缺少高度和宽度.另一个对象可能会模糊它.有关更多详细信息,快速Google搜索会显示这一点,甚至还包括一个试图解决问题的库.(YMMV)
查看以下内容,这些内容可能与此问题重复,并提供了出色的答案,包括强大的John Resig的一些见解.但是,您的特定用例与标准用例略有不同,因此我将避免标记:
(编辑:OP说他是划伤页面,不创建他们,所以不适用)更好的选择?将元素的可见性绑定到模型属性,并始终使可视化取决于该模型,就像Angular对ng-show所做的那样.你可以使用你想要的任何工具来做到这一点:Angular,普通的JS,等等.更好的是,您可以随着时间的推移更改DOM实现,但您始终能够从模型而不是DOM中读取状态.从DOM中读出你的真相很糟糕.而且很慢.更好的方法是检查模型,并相信您的实现以确保DOM状态反映模型.(并使用自动化测试来确认该假设.)
ohad navon 的回答的一点补充。
如果元素的中心属于另一个元素,我们将找不到它。
所以要确保发现元素的其中一个点是可见的
function isElementVisible(elem) {
if (!(elem instanceof Element)) throw Error('DomUtil: elem is not an element.');
const style = getComputedStyle(elem);
if (style.display === 'none') return false;
if (style.visibility !== 'visible') return false;
if (style.opacity === 0) return false;
if (elem.offsetWidth + elem.offsetHeight + elem.getBoundingClientRect().height +
elem.getBoundingClientRect().width === 0) {
return false;
}
var elementPoints = {
'center': {
x: elem.getBoundingClientRect().left + elem.offsetWidth / 2,
y: elem.getBoundingClientRect().top + elem.offsetHeight / 2
},
'top-left': {
x: elem.getBoundingClientRect().left,
y: elem.getBoundingClientRect().top
},
'top-right': {
x: elem.getBoundingClientRect().right,
y: elem.getBoundingClientRect().top
},
'bottom-left': {
x: elem.getBoundingClientRect().left,
y: elem.getBoundingClientRect().bottom
},
'bottom-right': {
x: elem.getBoundingClientRect().right,
y: elem.getBoundingClientRect().bottom
}
}
for(index in elementPoints) {
var point = elementPoints[index];
if (point.x < 0) return false;
if (point.x > (document.documentElement.clientWidth || window.innerWidth)) return false;
if (point.y < 0) return false;
if (point.y > (document.documentElement.clientHeight || window.innerHeight)) return false;
let pointContainer = document.elementFromPoint(point.x, point.y);
if (pointContainer !== null) {
do {
if (pointContainer === elem) return true;
} while (pointContainer = pointContainer.parentNode);
}
}
return false;
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
389836 次 |
最近记录: |