div - saber si un elemento es visible javascript
¿Cómo puedo verificar si un elemento es realmente visible con JavaScript? (17)
Esta pregunta ya tiene una respuesta aquí:
- Verificar si el elemento está visible en DOM 16 respuestas
En JavaScript, ¿cómo verificaría si un elemento es realmente visible?
No solo me refiero a verificar la visibility
y display
atributos de display
. Quiero decir, verificar que el elemento no sea
-
visibility: hidden
odisplay: none
- debajo de otro elemento
- desplazado por el borde de la pantalla
Por razones técnicas, no puedo incluir ningún script. Sin embargo, puedo usar Prototype tal como está en la página.
Aquí hay un script de muestra y un caso de prueba. Cubiertas de elementos posicionados, visibilidad: oculta, pantalla: ninguna. No probó el índice Z, suponga que funciona.
<!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>
Aquí hay una parte de la respuesta que le dice si un elemento está en la ventana gráfica. Es posible que deba verificar si no hay nada encima utilizando elementFromPoint, pero es un poco más largo.
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;
}
Captura los eventos mouse-drag y viewport (onmouseup, onresize, onscroll).
Cuando finalice un arrastre haga una comparación del límite del elemento arrastrado con todos los "elementos de interés" (es decir, los elementos con la clase "dont_hide" o una matriz de identificadores). Haga lo mismo con window.onscroll y window.onresize. Marque cualquier elemento oculto con un atributo especial o nombre de clase o simplemente realice cualquier acción que desee en ese momento.
Las pruebas ocultas son bastante fáciles. Para "totalmente oculto", desea saber si TODAS las esquinas están dentro del límite del elemento arrastrado o fuera de la ventana gráfica. Para parcialmente oculto, está buscando una esquina única que coincida con la misma prueba.
Como señaló jkl, comprobar la visibilidad o visualización del elemento no es suficiente. Tienes que verificar sus antepasados. El selenio hace esto cuando verifica la visibilidad en un elemento.
Consulte el método Selenium.prototype.isVisible en el archivo selenium-api.js.
http://svn.openqa.org/svn/selenium-on-rails/selenium-on-rails/selenium-core/scripts/selenium-api.js
Esto es lo que tengo hasta ahora. Cubre tanto 1 como 3. Sin embargo, sigo luchando con 2 ya que no estoy familiarizado con Prototype (soy más un tipo de jQuery).
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;
}
Interesante pregunta.
Este sería mi enfoque.
- En primer lugar, compruebe que element.style.visibility! == ''hidden'' && element.style.display! == ''none''
- Luego pruebe con document.elementFromPoint (element.offsetLeft, element.offsetTop) si el elemento devuelto es el elemento que espero, esto es difícil de detectar si un elemento se superpone por completo.
- Finalmente pruebe si offsetTop y offsetLeft están ubicados en la ventana gráfica teniendo en cuenta las compensaciones de desplazamiento.
Espero eso ayude.
La biblioteca de elementos de Prototype es una de las bibliotecas de consulta más potentes en cuanto a los métodos. Te recomiendo que revises la API.
Algunos consejos:
Verificar la visibilidad puede ser
Element.getStyle()
, pero puede usar el métodoElement.visible()
métodosElement.visible()
combinados en una función personalizada. CongetStyle()
puede verificar el estilo calculado real.No sé exactamente a qué te refieres con "debajo" :) Si quieres decir que tiene un ancestro específico, por ejemplo, un div envoltorio, puedes usar
Element.up(cssRule)
:var child = $("myparagraph"); if(!child.up("mywrapper")){ // I lost my mom! } else { // I found my mom! }
Si desea verificar los elementos secundarios del elemento secundario, puede hacerlo también:
var child = $("myparagraph"); if(!child.previous("mywrapper")){ // I lost my bro! } else { // I found my bro! }
De nuevo, Element lib puede ayudarlo si entiendo correctamente lo que quiere decir :) Puede verificar las dimensiones reales de la ventana gráfica y el desplazamiento de su elemento para que pueda calcular si su elemento está "fuera de pantalla".
¡Buena suerte!
Pegué un caso de prueba para prototypejs en http://gist.github.com/117125 . Parece que en tu caso simplemente no podemos confiar en getStyle()
en absoluto. Para maximizar la confiabilidad de la función isMyElementReallyVisible, debe combinar lo siguiente:
- Comprobando el estilo calculado (Dojo tiene una buena implementation que puedes tomar prestada)
- Comprobación del viewoffoffset (prototipo de método nativo)
- Comprobando el índice z para el problema "debajo" (en Internet Explorer puede tener errores)
La respuesta al primer punto es bastante simple si todavía puedes usar el prototipo (prototypejs):
$(''HtmlElementID'').visible(); returns: true|false
No creo que verificar la visibilidad y las propiedades de visualización del elemento sea lo suficientemente bueno para el requisito n. ° 1, incluso si usa currentStyle / getComputedStyle. También debes verificar los antepasados del elemento. Si un antepasado está oculto, también lo está el elemento.
No quisiera redirigirlo a jQuery (como suele hacerse), pero esta discusión sobre cuándo los elementos son realmente visibles es muy perspicaz.
Y desde jQuery 1.3.2 esto ya no es un problema .
No sé cuánto de esto es compatible con navegadores antiguos o no tan modernos, pero estoy usando algo como esto (sin necesidad de ninguna biblioteca):
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;
return 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;
}
Comprueba que el elemento tiene un área> 0 y luego comprueba si alguna parte del elemento está dentro de la ventana gráfica y que no está oculta "debajo" de otro elemento (en realidad solo verifico un punto único en el centro del elemento , por lo que no está 100% garantizado, pero podría modificar la secuencia de comandos para iterar sobre todos los puntos del elemento, si realmente necesita ...).
Actualizar
Función modificada on_top que verifica cada píxel:
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;
};
No sé sobre el rendimiento :)
Para el punto 2.
Veo que nadie ha sugerido usar document.elementFromPoint(x,y)
, para mí es la manera más rápida de probar si un elemento está anidado u oculto por otro. Puede pasar las compensaciones del elemento objetivo a la función.
Aquí está la página de prueba de PPK en elementFromPoint .
Pruebe element.getBoundingClientRect()
. Devolverá un objeto con propiedades
- fondo
- parte superior
- derecho
- izquierda
- ancho - dependiente del navegador
- altura - dependiente del navegador
Compruebe que el ancho y el alto del BoundingClientRect
del elemento no sean cero, que es el valor de elementos ocultos o no visibles. Si los valores son mayores que cero, el elemento debe ser visible en el cuerpo. A continuación, compruebe si la propiedad bottom
es inferior a screen.height
lo que implicaría que el elemento está dentro de la ventana gráfica. (Técnicamente, también debería tener en cuenta la parte superior de la ventana del navegador, incluida la barra de búsqueda, los botones, etc.)
Puede usar las propiedades clientHeight o clientWidth
function isViewable(element){
return (element.clientHeight > 0);
}
Una forma de hacerlo es:
isVisible(elm) {
while(elm.tagName != ''BODY'') {
if(!$(elm).visible()) return false;
elm = elm.parentNode;
}
return true;
}
Créditos: https://github.com/atetlaw/Really-Easy-Field-Validation/blob/master/validation.js#L178
Verifique los elementos ''propiedad offsetHeight. Si es más de 0, es visible. Nota: este enfoque no cubre una situación cuando se establece visibilidad: estilo oculto. Pero ese estilo es algo extraño de todos modos.
/**
* 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 <[email protected]>
*/
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;
}