Как проверить, действительно ли элемент отображается с помощью JavaScript?

В JavaScript, как бы вы проверили, действительно ли элемент виден?

Я не просто хочу проверить атрибуты visibility и display. Я имею в виду, проверяя, что элемент не

  • visibility: hidden или display: none
  • под другим элементом
  • прокручивается с края экрана.

По техническим причинам я не могу включить никаких скриптов. Однако я могу использовать Prototype, как это уже делается на странице.

Ответ 1

Для точки 2.

Я вижу, что никто не предложил использовать document.elementFromPoint(x,y), для меня это самый быстрый способ проверить, является ли элемент вложенным или скрытым другим. Вы можете передать смещения целевого элемента в функцию.

Здесь тестовая страница PPK на elementFromPoint.

Ответ 2

Я не знаю, сколько из них поддерживается в старых или не-современных браузерах, но я использую что-то вроде этого (без файлов для любых библиотек):

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% гарантирован - но вы можете просто изменить script на итерацию по всем точкам элемента, если вам действительно нужно...).

Update

Измененная функция 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;
};

Не знаю о производительности:)

Ответ 3

Как указал jkl, проверки видимости или отображения элемента недостаточно. Вам нужно проверить своих предков. Selenium делает это, когда проверяет видимость элемента.

Проверьте метод Selenium.prototype.isVisible в файле selenium-api.js.

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

Ответ 4

Это то, что у меня есть до сих пор. Он охватывает как 1, так и 3. Я все еще борется с 2, так как я не знаком с Prototype (я больше похожий тип 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;
}

Ответ 5

Интересный вопрос.

Это будет мой подход.

  • Сначала проверьте, что element.style.visibility! == 'hidden' && & element.style.display! == 'none'
  • Затем протестируйте с помощью document.elementFromPoint(element.offsetLeft, element.offsetTop), если возвращаемый элемент - это элемент, который я ожидаю, это сложно определить, полностью ли перекрывается элемент.
  • Наконец, если offsetTop и offsetLeft расположены в окне просмотра, что учитывает смещения прокрутки.

Надеюсь, что это поможет.

Ответ 6

Прототип Библиотека элементов является одной из самых мощных библиотек запросов с точки зрения методов. Я рекомендую вам проверить API.

Несколько советов:

  • Проверка видимости может быть болью, но вы можете использовать методы Element.getStyle() и Element.visible(), объединенные в пользовательскую функцию. С помощью getStyle() вы можете проверить фактический вычисленный стиль.

  • Я не знаю точно, что вы подразумеваете под "снизу":) Если вы имели в виду, что у него есть определенный предок, например, обертка 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!
    }
    
  • Опять же, Element lib может помочь вам, если я правильно понимаю, что вы имеете в виду:) Вы можете проверить фактические размеры окна просмотра и смещение вашего элемента, чтобы вы могли рассчитать, является ли ваш элемент "выключен".

Удачи!

Я вставил тестовый пример для prototypejs в http://gist.github.com/117125. Кажется, в вашем случае мы просто не можем доверять getStyle() вообще. Для максимизации надежности функции isMyElementReallyVisible вы должны комбинировать следующее:

  • Проверка вычисленного стиля (dojo имеет приятную реализацию, которую вы можете взять)
  • Проверка вида viewportoffset (собственный прототип метода)
  • Проверка z-индекса для проблемы "ниже" (в Internet Explorer может быть ошибкой)

Ответ 9

Поймайте события перетаскивания мышью и просмотра (onmouseup, onresize, onscroll).

Когда перетаскивание заканчивается, выполняется сравнение границы перетаскиваемого элемента со всеми "элементами интереса" (т.е. элементами с классом "dont_hide" или массивом идентификаторов). Сделайте то же самое с window.onscroll и window.onresize. Пометьте любые элементы, скрытые специальным атрибутом или именем класса, или просто выполните любое действие, которое вы хотите, и там.

Скрытые тесты довольно просты. Для "полностью скрытого" вы хотите знать, ВСЕ ли углы находятся внутри границы перетаскиваемого элемента или вне области просмотра. Для частичного скрытия вы ищете один угол, соответствующий одному и тому же тесту.

Ответ 10

Я не думаю, что проверка свойств видимости и отображения элемента достаточно хороша для требования №1, даже если вы используете currentStyle/getComputedStyle. Вы также должны проверить предков элемента. Если предок скрыт, то и элемент.

Ответ 11

Проверить свойства offsetHeight элементов. Если оно больше 0, оно видно. Примечание: этот подход не охватывает ситуацию, когда видимость: скрытый стиль установлен. Но этот стиль - это что-то странное.

Ответ 12

Вот пример script и тестовый пример. Обложки позиционированных элементов, видимые: скрытые, отображение: нет. Не тестировал z-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>

Ответ 13

/**
 * Checks display and visibility of elements and it 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;
}

Ответ 14

Вы можете использовать свойства clientHeight или clientWidth

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

Ответ 15

Попробуйте element.getBoundingClientRect(). Он вернет объект со свойствами

  • нижней
  • верхний
  • вправо
  • влево
  • ширина - зависит от браузера
  • высота - зависит от браузера

Убедитесь, что ширина и высота элемента BoundingClientRect не равны нулю, что является значением скрытых или невидимых элементов. Если значения больше нуля, элемент должен быть видимым в теле. Затем проверьте, имеет ли свойство bottom меньше, чем screen.height, что означает, что элемент находится в окне просмотра. (Технически вам также придется учитывать верх окна браузера, включая панель поиска, кнопки и т.д.)

Ответ 16

Ответ на первый вопрос довольно прост, если вы все еще можете использовать прототип (prototypejs):

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

Ответ 17

Вот часть ответа, в котором говорится, что элемент находится в окне просмотра. Вам может потребоваться проверить, нет ли чего-то поверх него, используя 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
}