Jak sprawdzić, czy element jest naprawdę widoczny w JavaScript? [duplikat]

to pytanie ma już odpowiedzi tutaj : sprawdź czy element jest widoczny w DOM (19 odpowiedzi) Zamknięty 4 lata temu .

W JavaScript, jak sprawdzić, czy element jest rzeczywiście widoczny?

Nie chodzi mi tylko o sprawdzanie atrybutów visibility i display. Chodzi mi o sprawdzenie czy element nie jest

  • visibility: hidden lub display: none
  • pod innym elementem
  • przewijanie krawędzi ekranu

Z przyczyn technicznych nie mogę dołączyć żadnych skryptów. Mogę jednak użyć Prototype Jak jest na stronie już.

Author: Peter Mortensen, 2009-04-01

15 answers

Dla punktu 2.

Widzę, że nikt nie zasugerował użycia document.elementFromPoint(x,y), dla mnie jest to najszybszy sposób, aby sprawdzić, czy element jest zagnieżdżony lub ukryty przez inny. Można przekazać przesunięcia elementu docelowego do funkcji.

Oto strona testowa PPK na elementFromPoint .

Z dokumentacji MDN :

Metoda elementFromPoint() - dostępna zarówno w dokumencie, jak i obiektach ShadowRoot-zwraca najwyższy Element o podanych współrzędnych (względem viewport).

 100
Author: Christophe Eblé,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-12-01 10:20:07

Nie wiem, ile z tego jest obsługiwane w starszych lub nie-tak-nowoczesnych przeglądarkach, ale używam czegoś takiego (bez neeed dla żadnych bibliotek):

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

Sprawdza, czy element ma obszar > 0, a następnie sprawdza, czy jakakolwiek część elementu znajduje się w viewporcie i czy nie jest ukryta " pod " innym elementem (w rzeczywistości sprawdzam tylko jeden punkt w środku elementu, więc nie jest to w 100% pewne -- ale można po prostu zmodyfikować skrypt, aby punkty elementu, jeśli naprawdę trzeba...).

Update

Zmodyfikowana funkcja on_top sprawdzająca każdy piksel:

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

Nie znam się na występie:)

 39
Author: Tobias,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-16 12:44:17

Jak zauważył jkl, sprawdzanie widoczności lub wyświetlania elementu nie wystarczy. Musisz sprawdzić jego przodków. Selen robi to, gdy sprawdza widoczność na elemencie.

Zobacz metodę selenu.prototyp.jest widoczny w API selenu.plik js.

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

 7
Author: Jason Tillery,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-17 06:39:19

Ciekawe pytanie.

To byłoby moje podejście.

  1. na początku sprawdź ten element.styl.widoczność != = 'hidden' & & element.styl.Pokaż != = "brak"
  2. następnie przetestuj ZA POMOCĄ dokumentu.elementFromPoint(element.offsetLeft, element.offsetTop) jeśli zwracany element jest elementem, którego oczekuję, jest to trudne do wykrycia, jeśli element całkowicie nakłada się na inny.
  3. wreszcie sprawdzić, czy offsetTop i offsetLeft znajdują się w viewporcie, biorąc przesunięcia przewijania do konto.

Mam nadzieję, że to pomoże.

 3
Author: Christophe Eblé,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-24 18:33:39

To jest to, co mam do tej pory. Obejmuje zarówno 1, jak i 3. Jestem jednak nadal zmaga się z 2, ponieważ nie jestem tak obeznany z prototypu (Jestem bardziej Typ jQuery facet).

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;
}
 3
Author: Pim Jager,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-30 17:04:51

Prototype ' s Element library jest jedną z najpotężniejszych bibliotek zapytań pod względem metod. Polecam zapoznać się z API.

Kilka wskazówek:

  1. Sprawdzanie widoczności może być uciążliwe, ale możesz użyć metod Element.getStyle() i Element.visible() połączonych w niestandardową funkcję. Za pomocą getStyle() Możesz sprawdzić rzeczywisty obliczony styl.

  2. Nie wiem dokładnie co masz na myśli przez "pod spodem":) jeśli chodziło Ci o to, że ma określony przodek, dla przykład, wrapper div, możesz użyć Element.up(cssRule):

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

    Jeśli chcesz sprawdzić rodzeństwo elementu potomnego, możesz to zrobić również:

    var child = $("myparagraph");
    if(!child.previous("mywrapper")){
      // I lost my bro!
    } 
    else {
      // I found my bro!
    }
    
  3. Ponownie, Element lib może Ci pomóc, jeśli dobrze rozumiem, co masz na myśli:) możesz sprawdzić rzeczywiste wymiary viewportu i przesunięcie twojego elementu , więc możesz obliczyć, czy twój element jest "poza ekranem".

Powodzenia!

Wkleiłem przypadek testowy dla prototypejs na http://gist.github.com/117125 . wydaje się, że w Twoim przypadku po prostu nie możemy w ogóle ufać getStyle(). Aby zmaksymalizować niezawodność funkcji isMyElementReallyVisible należy połączyć następujące wartości:

  • sprawdzanie stylu obliczeniowego (dojo ma ładną implementację którą możesz pożyczyć)
  • sprawdzanie viewportoffset (prototype native method)
  • sprawdzanie indeksu z pod kątem problemu "pod spodem" (pod Internet Explorerem może być buggy)
 2
Author: yaanno,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-30 17:02:15

Jednym ze sposobów jest:

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

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

 1
Author: umpirsky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-12 06:54:55
/**
 * 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;
}
 1
Author: Oleksandr Knyga,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-11 16:07:18

Możesz użyć właściwości clienttheight lub clientWidth

function isViewable(element){
  return (element.clientHeight > 0);
}
 1
Author: fred,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-13 14:33:44

Spróbuj element.getBoundingClientRect(). Zwróci obiekt o właściwościach

  • bottom
  • top
  • prawo
  • left
  • width -- browser dependent
  • height -- browser dependent

Sprawdź, czy szerokość i Wysokość elementu BoundingClientRect nie są równe zeru, co jest wartością elementów ukrytych lub niewidocznych. Jeżeli wartości są większe od zera, element powinien być widoczny w ciele. Następnie sprawdź, czy właściwość bottom jest mniejsza niż screen.height, co oznaczałoby, że element jest z wizjerem. (Technicznie trzeba by również uwzględnić górną część okna przeglądarki, w tym pasek wyszukiwania, przyciski itp.)

 1
Author: j_v_wow_d,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-05 05:13:12

Catch Mouse-przeciągnij i zobacz zdarzenia (onmouseup, onresize, onscroll).

Po zakończeniu przeciągania wykonaj porównanie granicy przeciąganego elementu ze wszystkimi "elementami interesującymi" (tj. elementami z klasą "dont_hide" lub tablicą identyfikatorów). Zrób to samo z oknem.onscroll i window.onresize. Zaznacz wszystkie ukryte elementy specjalnym atrybutem lub nazwą klasy lub po prostu wykonaj dowolną akcję.

Ukryte testy są dość łatwe. Dla "totally hidden" chcesz dowiedz się, czy wszystkie rogi znajdują się wewnątrz granicy przeciąganego elementu lub poza punktem widokowym. Dla częściowo ukrytego szukasz pojedynczego rogu pasującego do tego samego testu.

 0
Author: SpliFF,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-24 14:13:56

Nie sądzę, aby sprawdzanie własnej widoczności i właściwości wyświetlania elementu było wystarczająco dobre dla wymagań #1, nawet jeśli używasz currentStyle / getComputedStyle. Musisz również sprawdzić przodków elementu. Jeśli przodek jest ukryty, to również element.

 0
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-09-21 16:16:05

Sprawdź właściwość offsetHeight elementów. Jeśli jest więcej niż 0, jest widoczny. Uwaga: to podejście nie obejmuje sytuacji, gdy ustawiony jest styl visibility:hidden. Ale ten styl i tak jest czymś dziwnym.

 -1
Author: Sergey Ilinsky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-01 09:34:15

Oto przykładowy skrypt i przypadek testowy. Obejmuje elementy pozycjonowane, widoczność: ukryta, Wyświetlacz: Brak. Nie testowałem z-index, Załóżmy, że działa.

<!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>
 -1
Author: Mr. Shiny and New 安宇,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-25 15:45:19

Oto część odpowiedzi, która informuje, czy element znajduje się w widoku. Być może będziesz musiał sprawdzić, czy nie ma nic na nim za pomocą elementFromPoint, ale jest to nieco dłuższe.

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;
}
 -2
Author: MoOx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-07 05:54:52