如何检查一个元素是否真的可以用JavaScript显示?

在JavaScript中,如何检查元素是否真的可见?

我不只是在检查visibilitydisplay属性。 我的意思是,检查元素不是

  • visibility: hiddendisplay: none
  • 在另一个元素之下
  • 滚动屏幕的边缘

由于技术原因,我不能包含任何脚本。 但是,我可以使用Prototype,因为它已经在页面上了。

对于第二点。

我发现没有人build议使用document.elementFromPoint(x,y)对我来说,testing一个元素是否被另一个元素嵌套或隐藏是最快的方法。 您可以将目标元素的偏移量传递给函数。

这里是elementFromPoint上的PPKtesting页面。

我不知道有多less这是在旧的或不那么现代的浏览器支持,但我使用的是这样的(没有任何图书馆neeed):

 function visible(element) { if (element.offsetWidth === 0 || element.offsetHeight === 0) return false; var height = document.documentElement.clientHeight, rects = element.getClientRects(), on_top = function(r) { var x = (r.left + r.right)/2, y = (r.top + r.bottom)/2; document.elementFromPoint(x, y) === element; }; for (var i = 0, l = rects.length; i < l; i++) { var r = rects[i], in_viewport = r.top > 0 ? r.top <= height : (r.bottom > 0 && r.bottom <= height); if (in_viewport && on_top(r)) return true; } return false; } 

它检查元素是否具有大于0的区域,然后检查元素的任何部分是否在视口内,而不是隐藏在另一个元素“下”(实际上,我只检查元素中心的单个点,所以它不是100%的保证 – 但你可以修改脚本来遍历元素的所有点,如果你真的需要…)。

更新

修改on_top函数检查每个像素:

 on_top = function(r) { for (var x = Math.floor(r.left), x_max = Math.ceil(r.right); x <= x_max; x++) for (var y = Math.floor(r.top), y_max = Math.ceil(r.bottom); y <= y_max; y++) { if (document.elementFromPoint(x, y) === element) return true; } return false; }; 

不知道性能:)

jkl指出,检查元素的可见性或显示是不够的。 你必须检查它的祖先。 Selenium在validation元素的可见性时执行此操作。

在selenium-api.js文件中查看Selenium.prototype.isVisible方法。

http://svn.openqa.org/svn/selenium-on-rails/selenium-on-rails/selenium-core/scripts/selenium-api.js

有趣的问题。

这将是我的做法。

  1. 首先检查一下element.style.visibility!=='hidden'&& element.style.display!=='none'
  2. 然后使用document.elementFromPoint(element.offsetLeft,element.offsetTop)进行testing,如果返回的元素是我期望的元素,那么检测元素是否完全重叠是非常棘手的。
  3. 最后,testingoffsetTop和offsetLeft是否位于视口中,考虑了滚动偏移量。

希望它有帮助。

这是我迄今为止。 它涵盖了1和3.但是我还是挣扎着2,因为我不熟悉Prototype(我更像是一个jQuerytypes的人)。

 function isVisible( elem ) { var $elem = $(elem); // First check if elem is hidden through css as this is not very costly: if ($elem.getStyle('display') == 'none' || $elem.getStyle('visibility') == 'hidden' ) { //elem is set through CSS stylesheet or inline to invisible return false; } //Now check for the elem being outside of the viewport var $elemOffset = $elem.viewportOffset(); if ($elemOffset.left < 0 || $elemOffset.top < 0) { //elem is left of or above viewport return false; } var vp = document.viewport.getDimensions(); if ($elemOffset.left > vp.width || $elemOffset.top > vp.height) { //elem is below or right of vp return false; } //Now check for elements positioned on top: //TODO: Build check for this using Prototype... //Neither of these was true, so the elem was visible: return true; } 

Prototype的元素库是这些方法中function最强大的查询库之一。 我build议你检查一下API。

一些提示:

  1. 检查可见性可能很痛苦,但可以将Element.getStyle()方法和Element.visible()方法组合到一个自定义函数中。 用getStyle()你可以检查实际的计算风格。

  2. 我不知道你的意思是“底下”:)如果你的意思是它有一个特定的祖先,例如,一个包装div,你可以使用Element.up(cssRule)

     var child = $("myparagraph"); if(!child.up("mywrapper")){ // I lost my mom! } else { // I found my mom! } 

    如果你想检查子元素的兄弟姐妹,你也可以这样做:

     var child = $("myparagraph"); if(!child.previous("mywrapper")){ // I lost my bro! } else { // I found my bro! } 
  3. 同样,元素库可以帮助你,如果我正确理解你的意思:)你可以检查视口的实际尺寸和你的元素的偏移,所以你可以计算,如果你的元素是“屏幕外”。

祝你好运!

我在http://gist.github.com/117125上贴了prototypejs的testing用例。; 在你的情况下,我们完全不能相信getStyle() 。 为了最大化isMyElementReallyVisible函数的可靠性,您应该结合以下内容:

  • 检查计算的样式(dojo有一个很好的实现 ,你可以借用)
  • 检查viewportoffset(原生本地方法)
  • 检查z-index是否存在问题(在Internet Explorer下可能会出现问题)

一种方法是:

 isVisible(elm) { while(elm.tagName != 'BODY') { if(!$(elm).visible()) return false; elm = elm.parentNode; } return true; } 

积分: https : //github.com/atetlaw/Really-Easy-Field-Validation/blob/master/validation.js#L178

捕捉鼠标拖动和视口事件(onmouseup,onresize,onscroll)。

拖动结束时,将拖动的项目边界与所有“感兴趣的元素”(即具有“dont_hide”类或id数组的元素)进行比较。 用window.onscroll和window.onresize做同样的事情。 标记任何隐藏了特殊属性或类名的元素,或者简单地执行任何你想要的操作。

隐藏的testing非常简单。 对于“完全隐藏”,你想知道所有的angular落是在拖拽项目的边界内还是在视口之外。 对于部分隐藏你正在寻找一个angular落匹配相同的testing。

即使使用currentStyle / getComputedStyle,我也不认为检查元素自身的可见性和显示属性对于需求#1是足够好的。 你也必须检查元素的祖先。 如果祖先是隐藏的,元素也是如此。

我讨厌把你redirect到jQuery(就像经常这样做), 但是关于何时元素真正可见的讨论非常有见地。

而从jQuery 1.3.2这不再是一个问题 。

检查元素的offsetHeight属性。 如果它大于0,则可见。 注意:这种方法不包括当visibility:hidden style被设置的情况。 但是这种风格反正是奇怪的。

这是一个示例脚本和testing用例。 封面定位元素,可见性:隐藏,显示:无。 没有testingz-index,假设它工作。

 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title></title> <style type="text/css"> div { width: 200px; border: 1px solid red; } p { border: 2px solid green; } .r { border: 1px solid #BB3333; background: #EE9999; position: relative; top: -50px; height: 2em; } .of { overflow: hidden; height: 2em; word-wrap: none; } .of p { width: 100%; } .of pre { display: inline; } .iv { visibility: hidden; } .dn { display: none; } </style> <script src="http://www.prototypejs.org/assets/2008/9/29/prototype-1.6.0.3.js"></script> <script> function isVisible(elem){ if (Element.getStyle(elem, 'visibility') == 'hidden' || Element.getStyle(elem, 'display') == 'none') { return false; } var topx, topy, botx, boty; var offset = Element.positionedOffset(elem); topx = offset.left; topy = offset.top; botx = Element.getWidth(elem) + topx; boty = Element.getHeight(elem) + topy; var v = false; for (var x = topx; x <= botx; x++) { for(var y = topy; y <= boty; y++) { if (document.elementFromPoint(x,y) == elem) { // item is visible v = true; break; } } if (v == true) { break; } } return v; } window.onload=function() { var es = Element.descendants('body'); for (var i = 0; i < es.length; i++ ) { if (!isVisible(es[i])) { alert(es[i].tagName); } } } </script> </head> <body id='body'> <div class="s"><p>This is text</p><p>More text</p></div> <div class="r">This is relative</div> <div class="of"><p>This is too wide...</p><pre>hidden</pre> <div class="iv">This is invisible</div> <div class="dn">This is display none</div> </body> </html> 
 /** * Checks display and visibility of elements and it's parents * @param DomElement el * @param boolean isDeep Watch parents? Default is true * @return {Boolean} * * @author Oleksandr Knyga <oleksandrknyga@gmail.com> */ function isVisible(el, isDeep) { var elIsVisible = true; if("undefined" === typeof isDeep) { isDeep = true; } elIsVisible = elIsVisible && el.offsetWidth > 0 && el.offsetHeight > 0; if(isDeep && elIsVisible) { while('BODY' != el.tagName && elIsVisible) { elIsVisible = elIsVisible && 'hidden' != window.getComputedStyle(el).visibility; el = el.parentElement; } } return elIsVisible; } 

您可以使用clientHeight或clientWidth属性

 function isViewable(element){ return (element.clientHeight > 0); } 

尝试element.getBoundingClientRect() 。 它将返回一个带有属性的对象

  • 底部
  • 最佳
  • 剩下
  • 宽度 – 依赖于浏览器
  • 高度 – 依赖于浏览器

检查元素的BoundingClientRect的宽度和高度是否为零,这是隐藏或不可见元素的值。 如果值大于零,则元素应该在主体中可见。 然后检查bottom属性是否小于screen.height这意味着该元素与视口。 (从技术上讲,您还必须考虑浏览器窗口的顶部,包括search栏,button等)

这是响应的一部分,告诉你一个元素是否在视口中。 你可能需要使用elementFromPoint来检查它是否没有任何东西,但是它有点长。

 function isInViewport(element) { var rect = element.getBoundingClientRect() var windowHeight = window.innerHeight || document.documentElement.clientHeight var windowWidth = window.innerWidth || document.documentElement.clientWidth return rect.bottom > 0 && rect.top < windowHeight && rect.right > 0 && rect.left < windowWidth } 

如果你仍然能够使用原型(prototypejs),那么第一点的答案是非常简单的:

 $('HtmlElementID').visible(); returns: true|false