javascript 检查元素是否在 DOM 中可见

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19669786/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 16:25:17  来源:igfitidea点击:

Check if element is visible in DOM

javascriptdom

提问by Hommer Smith

Is there any way that I can check if an element is visible in pure JS (no jQuery) ?

有什么方法可以检查元素在纯 JS(无 jQuery)中是否可见?

So, for example, in this page: Performance Bikes, if you hover over Deals (on the top menu), a window of deals appear, but at the beginning it was not shown. It is in the HTML but it is not visible.

因此,例如,在此页面中:Performance Bikes,如果您将鼠标悬停在 Deals(在顶部菜单上)上,则会出现一个交易窗口,但在开始时并未显示。它在 HTML 中,但不可见。

So, given a DOM element, how can I check if it is visible or not? I tried:

那么,给定一个 DOM 元素,我如何检查它是否可见?我试过:

window.getComputedStyle(my_element)['display']);

but it doesn't seem to be working. I wonder which attributes should I check. It comes to my mind:

但它似乎不起作用。我想知道我应该检查哪些属性。我想到了:

display !== 'none'
visibility !== 'hidden'

Any others that I might be missing?

还有其他我可能会失踪的吗?

回答by AlexZ

According to this MDN documentation, an element's offsetParentproperty will return nullwhenever it, or any of its parents, is hidden via the display style property. Just make sure that the element isn't fixed. A script to check this, if you have no position: fixed;elements on your page, might look like:

根据此 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)
}

On the other hand, if you dohave position fixed elements that might get caught in this search, you will sadly (and slowly) have to use window.getComputedStyle(). The function in that case might be:

另一方面,如果您确实有可能在此搜索中被捕获的位置固定元素,您将遗憾地(并且慢慢地)不得不使用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')
}

Option #2 is probably a little more straightforward since it accounts for more edge cases, but I bet its a good deal slower, too, so if you have to repeat this operation many times, best to probably avoid it.

选项#2 可能更简单一些,因为它考虑了更多的边缘情况,但我敢打赌它也慢很多,所以如果你必须多次重复这个操作,最好避免它。

回答by guy mograbi

All the other solutions broke for some situation for me..

对我来说,所有其他解决方案都因某些情况而崩溃。

See the winning answer breaking at:

查看获胜答案:

http://plnkr.co/edit/6CSCA2fe4Gqt4jCBP2wu?p=preview

http://plnkr.co/edit/6CSCA2fe4Gqt4jCBP2wu?p=preview

Eventually, I decided that the best solution was $(elem).is(':visible')- however, this is not pure javascript. it is jquery..

最终,我决定最好的解决方案是$(elem).is(':visible')- 然而,这不是纯 javascript。这是jquery..

so I peeked at their source and found what I wanted

所以我偷看了他们的来源并找到了我想要的

jQuery.expr.filters.visible = function( elem ) {
    return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );
};

This is the source: https://github.com/jquery/jquery/blob/master/src/css/hiddenVisibleSelectors.js

这是来源:https: //github.com/jquery/jquery/blob/master/src/css/hiddenVisibleSelectors.js

回答by Ohad Navon

If you're interested in visible by the user:

如果您对用户可见感兴趣:

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;
}

Tested on (using mochaterminology):

测试(使用摩卡术语):

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;
    });
});

回答by Md. Ashaduzzaman

This may help :Hide the element by positioning it on far most left position and then check the offsetLeft property. If you want to use jQuery you can simply check the :visibleselector and get the visibility state of the element.

这可能有帮助:通过将元素定位在最左边的位置来隐藏元素,然后检查 offsetLeft 属性。如果你想使用 jQuery,你可以简单地检查:visible选择器并获取元素的可见性状态。

HTML :

HTML :

<div id="myDiv">Hello</div>

CSS :

CSS :

<!-- for javaScript-->
#myDiv{
   position:absolute;
   left : -2000px;
}

<!-- for jQuery -->
#myDiv{
    visibility:hidden;
}

javaScript :

脚本:

var myStyle = document.getElementById("myDiv").offsetLeft;

if(myStyle < 0){
     alert("Div is hidden!!");
}

jQuery :

jQuery :

if(  $("#MyElement").is(":visible") == true )
{  
     alert("Div is visible!!");        
}

jsFiddle

js小提琴

回答by Yvan

Use the same code as jQuery does:

使用与 jQuery 相同的代码:

jQuery.expr.pseudos.visible = function( elem ) {
    return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );
};

So, in a function:

所以,在一个函数中:

function isVisible(e) {
    return !!( e.offsetWidth || e.offsetHeight || e.getClientRects().length );
}

Works like a charm in my Win/IE10, Linux/Firefox.45, Linux/Chrome.52...

在我的 Win/IE10、Linux/Firefox.45、Linux/Chrome.52...

Many thanks to jQuery without jQuery!

非常感谢没有 jQuery 的 jQuery!

回答by Matthew

Combining a couple answers above:

结合上面的几个答案:

function isVisible (ele) {
    var style = window.getComputedStyle(ele);
    return  style.width !== "0" &&
    style.height !== "0" &&
    style.opacity !== "0" &&
    style.display!=='none' &&
    style.visibility!== 'hidden';
}

Like AlexZ said, this may be slower than some of your other options if you know more specifically what you're looking for, but this should catch all of the main ways elements are hidden.

就像 AlexZ 所说的那样,如果您更具体地知道要查找的内容,这可能比您的其他一些选项慢,但这应该可以捕获元素隐藏的所有主要方式。

But, it also depends what counts as visible for you. Just for example, a div's height can be set to 0px but the contents still visible depending on the overflow properties. Or a div's contents could be made the same color as the background so it is not visible to users but still rendered on the page. Or a div could be moved off screen or hidden behind other divs, or it's contents could be non-visible but the border still visible. To a certain extent "visible" is a subjective term.

但是,这也取决于什么对您来说是可见的。举个例子,一个 div 的高度可以设置为 0px 但内容仍然可见取决于溢出属性。或者可以将 div 的内容设置为与背景相同的颜色,这样用户看不到它,但仍然呈现在页面上。或者一个 div 可以移出屏幕或隐藏在其他 div 后面,或者它的内容可能不可见但边框仍然可见。在某种程度上,“可见”是一个主观术语。

回答by Munawwar

I've got a more performant solution compared to AlexZ's getComputedStyle() solutionwhen one has position 'fixed' elements, if one is willing to ignore some edge cases (check comments):

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;
}

Side note: Strictly speaking, "visibility" needs to be defined first. In my case, I am considering an element visible as long as I can run all DOM methods/properties on it without problems (even if opacity is 0 or CSS visibility property is 'hidden' etc).

旁注:严格来说,“可见性”需要首先定义。就我而言,我正在考虑一个可见的元素,只要我可以在其上运行所有 DOM 方法/属性而不会出现问题(即使不透明度为 0 或 CSS 可见性属性为“隐藏”等)。

回答by Vlada

If element is regular visible (display:block and visibillity:visible), but some parent container is hidden, then we can use clientWidthand clientHeightfor check that.

如果元素是常规可见的(display:block 和 visibillity:visible),但隐藏了一些父容器,那么我们可以使用clientWidthclientHeight进行检查。

function isVisible (ele) {
  return  ele.clientWidth !== 0 &&
    ele.clientHeight !== 0 &&
    ele.style.opacity !== 0 &&
    ele.style.visibility !== 'hidden';
}

Plunker (click here)

普朗克(点击这里)

回答by XML

If we're just collecting basic ways of detecting visibility, let me not forget:

如果我们只是收集检测可见性的基本方法,请不要忘记:

opacity > 0.01; // probably more like .1 to actually be visible, but YMMV

And as to how to obtain attributes:

至于如何获取属性:

element.getAttribute(attributename);

So, in your example:

所以,在你的例子中:

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 styleproperty. 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)

但是什么?它在这里不起作用。仔细观察,您会发现可见性不是作为元素的属性更新,而是使用style属性更新。这是尝试做你正在做的事情的许多问题之一。除其他外:您不能保证元素中确实有一些东西可以看到,仅仅因为它的可见性、显示和不透明度都具有正确的值。它仍然可能缺乏内容,或者可能缺乏高度和宽度。另一个对象可能会掩盖它。有关更多详细信息,快速谷歌搜索揭示了这一点,甚至包括一个尝试解决问题的库。(YMMV)

Check out the following, which are possible duplicates of this question, with excellent answers, including some insight from the mighty John Resig. However, your specific use-case is slightly different from the standard one, so I'll refrain from flagging:

查看以下内容,这些内容可能与此问题重复,并提供出色的答案,包括来自强大的 John Resig 的一些见解。但是,您的特定用例与标准用例略有不同,因此我将避免标记:

(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.)

(编辑:OP 说他在刮页面,而不是创建页面,所以下面不适用)更好的选择?将元素的可见性绑定到模型属性,并始终使可见性取决于该模型,就像 Angular 对 ng-show 所做的那样。你可以使用任何你想要的工具来做到这一点:Angular、纯 JS 等等。更好的是,您可以随着时间的推移更改 DOM 实现,但您始终能够从模型而不是 DOM 中读取状态。从 DOM 中读取真相是糟糕的。而且很慢。最好检查模型,并信任您的实现以确保 DOM 状态反映模型。(并使用自动化测试来确认该假设。)

回答by crisc82

The accepted answer did not worked for me.Year 2020 answer:

接受的答案对我不起作用。2020 年答案

1) The (elem.offsetParent !== null)method works fine in Firefox but not in Chrome. For Chrome "position: fixed;" will also make offsetParent return "null" even the element if visible in the page.

1) (elem.offsetParent !== null)方法在 Firefox 中工作正常,但在 Chrome 中无效。对于 Chrome “位置:固定;” 如果在页面中可见,即使元素也将使 offsetParent 返回“null”。

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>

you can see this guy megatest https://stackoverflow.com/a/11639664/4481831(run it with multiple browsers to see the differences).

你可以看到这个家伙 megest https://stackoverflow.com/a/11639664/4481831(用多个浏览器运行它以查看差异)。

2) The (getComputedStyle(elem).display !== 'none')do not work because the element can be invisible because one of the parents display property is set to none, getComputedStyle will not catch that.

2) (getComputedStyle(elem).display !== 'none')不起作用,因为元素可能不可见,因为父显示属性之一设置为 none,getComputedStyle 不会捕捉到它。

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>

3) 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, see more here

3) (elem.clientHeight !== 0)。此方法不受位置固定的影响,它还检查元素父元素是否不可见。但是它在没有 css 布局的简单元素方面存在问题,请在此处查看更多信息

Demo:

演示:

console.log(document.querySelector('#div1').clientHeight); //not zero
console.log(document.querySelector('#span1').clientHeight); //zero
<div id="div1">test1 div</div>
<span id="span1">test2 span</span>

4) The (elem.getClientRects().length !== 0)that seem to overpass 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.

4)这个(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);
<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>

CONCLUSION:So what I have showed you is that no method is perfect. To make a proper visibility check you must use a combination of the last 3 methods.

结论:所以我向您展示的是,没有任何方法是完美的。要进行适当的可见性检查,您必须结合使用最后 3 种方法。