有什么方法,我可以检查如果一个元素是可见的纯JS(没有jQuery) ?
因此,给定一个DOM元素,我如何检查它是否可见?我试着:
window.getComputedStyle(my_element)['display']);
但这似乎并不奏效。我想知道我应该检查哪些属性。我想到了:
display !== 'none'
visibility !== 'hidden'
还有我可能漏掉的吗?
有什么方法,我可以检查如果一个元素是可见的纯JS(没有jQuery) ?
因此,给定一个DOM元素,我如何检查它是否可见?我试着:
window.getComputedStyle(my_element)['display']);
但这似乎并不奏效。我想知道我应该检查哪些属性。我想到了:
display !== 'none'
visibility !== 'hidden'
还有我可能漏掉的吗?
当前回答
如果我们只是收集检测能见度的基本方法,让我不要忘记:
opacity > 0.01; // probably more like .1 to actually be visible, but YMMV
至于如何获取属性:
element.getAttribute(attributename);
所以,在你的例子中:
document.getElementById('snDealsPanel').getAttribute('visibility');
But wha? It doesn't work here. Look closer and you'll find that visibility is being updated not as an attribute on the element, but using the style property. This is one of many problems with trying to do what you're doing. Among others: you can't guarantee that there's actually something to see in an element, just because its visibility, display, and opacity all have the correct values. It still might lack content, or it might lack a height and width. Another object might obscure it. For more detail, a quick Google search reveals this, and even includes a library to try solving the problem. (YMMV)
看看下面的问题,它们可能是这个问题的副本,有很好的答案,包括来自强大的约翰·雷西格的一些见解。但是,您的特定用例与标准用例略有不同,因此我将避免标记:
如何判断一个DOM元素是否在当前视口中可见? 如何检查一个元素是否真的可见javascript?
(EDIT: OP SAYS HE'S SCRAPING PAGES, NOT CREATING THEM, SO BELOW ISN'T APPLICABLE) A better option? Bind the visibility of elements to model properties and always make visibility contingent on that model, much as Angular does with ng-show. You can do that using any tool you want: Angular, plain JS, whatever. Better still, you can change the DOM implementation over time, but you'll always be able to read state from the model, instead of the DOM. Reading your truth from the DOM is Bad. And slow. Much better to check the model, and trust in your implementation to ensure that the DOM state reflects the model. (And use automated testing to confirm that assumption.)
其他回答
如果元素是常规可见的(display:block和visibility:visible),但有些父容器是隐藏的,那么我们可以使用clientWidth和clienttheight来检查。
function isVisible (ele) {
return ele.clientWidth !== 0 &&
ele.clientHeight !== 0 &&
(ele.style.opacity !== '' ? parseFloat(ele.style.opacity) > 0 : true);
}
活塞(点击这里)
如果我们只是收集检测能见度的基本方法,让我不要忘记:
opacity > 0.01; // probably more like .1 to actually be visible, but YMMV
至于如何获取属性:
element.getAttribute(attributename);
所以,在你的例子中:
document.getElementById('snDealsPanel').getAttribute('visibility');
But wha? It doesn't work here. Look closer and you'll find that visibility is being updated not as an attribute on the element, but using the style property. This is one of many problems with trying to do what you're doing. Among others: you can't guarantee that there's actually something to see in an element, just because its visibility, display, and opacity all have the correct values. It still might lack content, or it might lack a height and width. Another object might obscure it. For more detail, a quick Google search reveals this, and even includes a library to try solving the problem. (YMMV)
看看下面的问题,它们可能是这个问题的副本,有很好的答案,包括来自强大的约翰·雷西格的一些见解。但是,您的特定用例与标准用例略有不同,因此我将避免标记:
如何判断一个DOM元素是否在当前视口中可见? 如何检查一个元素是否真的可见javascript?
(EDIT: OP SAYS HE'S SCRAPING PAGES, NOT CREATING THEM, SO BELOW ISN'T APPLICABLE) A better option? Bind the visibility of elements to model properties and always make visibility contingent on that model, much as Angular does with ng-show. You can do that using any tool you want: Angular, plain JS, whatever. Better still, you can change the DOM implementation over time, but you'll always be able to read state from the model, instead of the DOM. Reading your truth from the DOM is Bad. And slow. Much better to check the model, and trust in your implementation to ensure that the DOM state reflects the model. (And use automated testing to confirm that assumption.)
为了详细说明大家的精彩回答,下面是Mozilla Fathom项目中使用的实现:
/**
* Yield an element and each of its ancestors.
*/
export function *ancestors(element) {
yield element;
let parent;
while ((parent = element.parentNode) !== null && parent.nodeType === parent.ELEMENT_NODE) {
yield parent;
element = parent;
}
}
/**
* Return whether an element is practically visible, considering things like 0
* size or opacity, ``visibility: hidden`` and ``overflow: hidden``.
*
* Merely being scrolled off the page in either horizontally or vertically
* doesn't count as invisible; the result of this function is meant to be
* independent of viewport size.
*
* @throws {Error} The element (or perhaps one of its ancestors) is not in a
* window, so we can't find the `getComputedStyle()` routine to call. That
* routine is the source of most of the information we use, so you should
* pick a different strategy for non-window contexts.
*/
export function isVisible(fnodeOrElement) {
// This could be 5x more efficient if https://github.com/w3c/csswg-drafts/issues/4122 happens.
const element = toDomElement(fnodeOrElement);
const elementWindow = windowForElement(element);
const elementRect = element.getBoundingClientRect();
const elementStyle = elementWindow.getComputedStyle(element);
// Alternative to reading ``display: none`` due to Bug 1381071.
if (elementRect.width === 0 && elementRect.height === 0 && elementStyle.overflow !== 'hidden') {
return false;
}
if (elementStyle.visibility === 'hidden') {
return false;
}
// Check if the element is irrevocably off-screen:
if (elementRect.x + elementRect.width < 0 ||
elementRect.y + elementRect.height < 0
) {
return false;
}
for (const ancestor of ancestors(element)) {
const isElement = ancestor === element;
const style = isElement ? elementStyle : elementWindow.getComputedStyle(ancestor);
if (style.opacity === '0') {
return false;
}
if (style.display === 'contents') {
// ``display: contents`` elements have no box themselves, but children are
// still rendered.
continue;
}
const rect = isElement ? elementRect : ancestor.getBoundingClientRect();
if ((rect.width === 0 || rect.height === 0) && elementStyle.overflow === 'hidden') {
// Zero-sized ancestors don’t make descendants hidden unless the descendant
// has ``overflow: hidden``.
return false;
}
}
return true;
}
它检查每个父元素的不透明度、显示和矩形。
结合上面的几个答案:
function isVisible (ele) {
var style = window.getComputedStyle(ele);
return style.width !== "0" &&
style.height !== "0" &&
style.opacity !== "0" &&
style.display!=='none' &&
style.visibility!== 'hidden';
}
就像AlexZ说的,这可能会比你的一些其他选择更慢,如果你更具体地知道你在寻找什么,但这应该抓住所有隐藏元素的主要方式。
但是,这也取决于你认为什么是可见的。例如,一个div的高度可以设置为0px,但内容仍然可见,这取决于溢出属性。或者,可以将div的内容设置为与背景相同的颜色,这样用户就不会看到它,但仍然可以在页面上显示。或者一个div可以移出屏幕或隐藏在其他div后面,或者它的内容可以是不可见的,但边界仍然可见。在一定程度上,“可见”是一个主观术语。
公认的答案对我不起作用。
2020年分解。
The (elem.offsetParent !== null) method works fine in Firefox but not in Chrome. In Chrome position: fixed will also make offsetParent return null even the element if visible in the page. User Phrogz conducted a large test (2,304 divs) on elements with varying properties to demonstrate the issue. https://stackoverflow.com/a/11639664/4481831 . Run it with multiple browsers to see the differences. Demo: //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 <div id="hidden1" style="display:none;"></div> <div id="fixed1" style="position:fixed;"></div> The (getComputedStyle(elem).display !== 'none') does not work because the element can be invisible because one of the parents display property is set to none, getComputedStyle will not catch that. Demo: var child1 = document.querySelector('#child1'); console.log(getComputedStyle(child1).display); //child will show "block" instead of "none" <div id="parent1" style="display:none;"> <div id="child1" style="display:block"></div> </div> The (elem.clientHeight !== 0). This method is not influenced by position: fixed and it also check if element parents are not-visible. But it has problems with simple elements that do not have a css layout and inline elements, see more here Demo: console.log(document.querySelector('#inline1').clientHeight); //zero console.log(document.querySelector('#div1').clientHeight); //not zero console.log(document.querySelector('#span1').clientHeight); //zero <div id="inline1" style="display:inline">test1 inline</div> <div id="div1">test2 div</div> <span id="span1">test3 span</span> The (elem.getClientRects().length !== 0) may seem to solve the problems of the previous 3 methods. However it has problems with elements that use CSS tricks (other then display: none) to hide in the page. Demo 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); <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>
结论。
所以我向你们展示的是没有什么方法是完美的。要进行适当的可见性检查,必须结合使用后3种方法。