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

StackOverflow https://stackoverflow.com/questions/704758

  •  22-08-2019
  •  | 
  •  

Вопрос

На этот вопрос уже есть ответ здесь:

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

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

  • visibility: hidden или display: none
  • под другим элементом
  • прокрутил за край экрана

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

Это было полезно?

Решение

По пункту 2.

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

Вот тестовая страница PPK на элементFromPoint.

Другие советы

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

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

Он проверяет, что элемент имеет площадь > 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 делает это, когда проверяет видимость элемента.

Ознакомьтесь с методом Selenium.prototype.isVisible в файле selenium-api.js.

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), является ли возвращаемый элемент ожидаемым элементом. Трудно определить, полностью ли элемент перекрывает другой.
  3. Наконец, проверьте, расположены ли offsetTop и offsetLeft в области просмотра с учетом смещений прокрутки.

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

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

Прототип Библиотека элементов — одна из самых мощных библиотек запросов с точки зрения методов.Я рекомендую вам проверить 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. Опять же, Element lib может вам помочь, если я правильно понимаю, что вы имеете в виду :) Вы можете проверить актуальность размеры области просмотра и смещение вашего элемента чтобы вы могли рассчитать, находится ли ваш элемент «за кадром».

Удачи!

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

  • Проверяем вычисленный стиль (в додзё есть хороший выполнение что можно одолжить)
  • Проверка смещения области просмотра (собственный метод прототипа)
  • Проверка z-индекса на наличие проблемы «ниже» (в 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» или массивом идентификаторов).Сделайте то же самое с window.onscroll и window.onresize.Отметьте любые скрытые элементы специальным атрибутом или именем класса или просто выполните любое действие, которое захотите, прямо сейчас.

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

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

Мне не хотелось бы перенаправлять вас на jQuery (как это часто бывает), но это обсуждение о том, когда элементы действительно видимы, очень познавательно.

И с тех пор jQuery 1.3.2 Это больше не проблема.

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

Вот пример сценария и тестовый пример.Охватывает позиционированные элементы, видимость:скрыто, отображение:никто.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>
/**
 * 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 что будет означать, что элемент находится в области просмотра.(Технически вам также придется учитывать верхнюю часть окна браузера, включая панель поиска, кнопки и т. д.)

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

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

Вот часть ответа, которая сообщает вам, находится ли элемент в области просмотра.Возможно, вам придется проверить, нет ли чего-нибудь поверх него, используя 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;
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top