Как одним действием найти видимые элементы на странице

Поддержка
  • Запросить количество элементов и потом перебирать циклом на проверку каждого, виден ли элемент на странице, такой способ не предлагать, это очень долго.

    Как можно одним действием, получить количество видимых элементов на странице? Например на странице есть 5к элементов, 500 всего видимых, получить не все 5к, а именно 500 сразу в список

  • @Alexx5l6

    IntersectionObserver, надо тестить, но работать будет не сильно быстрее, я думаю. И все равно без цикла не обойтись, ну или я не знаю как.

    Решение в лоб отработало на этой странице почти мгновенно. Но в нем нет проверки что элемент не перекрыт чем-нибудь, не сливается с фоном ну или что имелось в виду под понятием "видимый". Техники понять это обсуждались на этом форуме.

    // Получаем все элементы на странице
    const allElements = document.body.getElementsByTagName('*');
    
    // Функция для проверки, видим ли элемент
    const isVisible = (elem) => {
      const rect = elem.getBoundingClientRect();
      const viewHeight = Math.max(window.innerHeight, document.documentElement.clientHeight);
      const viewWidth = Math.max(window.innerWidth, document.documentElement.clientWidth);
    
      // Проверяем, находится ли элемент в видимой части окна просмотра
      return !(rect.bottom < 0 || rect.top > viewHeight || rect.right < 0 || rect.left > viewWidth);
    };
    
    // Фильтруем видимые элементы
    const visibleElements = Array.from(allElements).filter(isVisible);
    
    console.log(visibleElements.length); // Количество видимых элементов
    console.log(visibleElements); // Массив видимых элементов
    
  • @sergerdn said in Как одним действием найти видимые элементы на странице:

    @Alexx5l6

    IntersectionObserver, надо тестить, но работать будет не сильно быстрее, я думаю. И все равно без цикла не обойтись, ну или я не знаю как.

    Решение в лоб отработало на этой странице почти мгновенно. Но в нем нет проверки что элемент не перекрыт чем-нибудь, не сливается с фоном ну или что имелось в виду под понятием "видимый". Техники понять это обсуждались на этом форуме.

    // Получаем все элементы на странице
    const allElements = document.body.getElementsByTagName('*');
    
    // Функция для проверки, видим ли элемент
    const isVisible = (elem) => {
      const rect = elem.getBoundingClientRect();
      const viewHeight = Math.max(window.innerHeight, document.documentElement.clientHeight);
      const viewWidth = Math.max(window.innerWidth, document.documentElement.clientWidth);
    
      // Проверяем, находится ли элемент в видимой части окна просмотра
      return !(rect.bottom < 0 || rect.top > viewHeight || rect.right < 0 || rect.left > viewWidth);
    };
    
    // Фильтруем видимые элементы
    const visibleElements = Array.from(allElements).filter(isVisible);
    
    console.log(visibleElements.length); // Количество видимых элементов
    console.log(visibleElements); // Массив видимых элементов
    

    Важный момент, этот способ не определит видимые элементы внутри фреймов

  • @sergerdn said in Как одним действием найти видимые элементы на странице:

    @Alexx5l6

    IntersectionObserver, надо тестить, но работать будет не сильно быстрее, я думаю. И все равно без цикла не обойтись, ну или я не знаю как.

    Решение в лоб отработало на этой странице почти мгновенно. Но в нем нет проверки что элемент не перекрыт чем-нибудь, не сливается с фоном ну или что имелось в виду под понятием "видимый". Техники понять это обсуждались на этом форуме.

    // Получаем все элементы на странице
    const allElements = document.body.getElementsByTagName('*');
    
    // Функция для проверки, видим ли элемент
    const isVisible = (elem) => {
      const rect = elem.getBoundingClientRect();
      const viewHeight = Math.max(window.innerHeight, document.documentElement.clientHeight);
      const viewWidth = Math.max(window.innerWidth, document.documentElement.clientWidth);
    
      // Проверяем, находится ли элемент в видимой части окна просмотра
      return !(rect.bottom < 0 || rect.top > viewHeight || rect.right < 0 || rect.left > viewWidth);
    };
    
    // Фильтруем видимые элементы
    const visibleElements = Array.from(allElements).filter(isVisible);
    
    console.log(visibleElements.length); // Количество видимых элементов
    console.log(visibleElements); // Массив видимых элементов
    

    Например, кнопка, если нажать на кнопку, всплывет меню с ссылками (это не видимые ссылки), т.е элемент в коде есть, но по нему кликнуть нельзя, пока не нажать на кнопку меню, чтобы всплыло подменю

  • window.scrollTo(0, 0)
    var bodyRect = document.body.getBoundingClientRect();
    
    var items = Array.prototype.slice.call(
      document.querySelectorAll('*')
    ).map(function(element) {
      var rect=element.getBoundingClientRect();
      return {
        element: element,
        include: (element.tagName === "BUTTON" || element.tagName === "A" || (element.onclick != null) || window.getComputedStyle(element).cursor == "pointer"),
        rect: {left: Math.max(rect.left - bodyRect.x, 0),
               top: Math.max(rect.top - bodyRect.y, 0),
               right: Math.min(rect.right - bodyRect.x, document.body.clientWidth),
               bottom: Math.min(rect.bottom - bodyRect.y, document.body.clientHeight)},
        text: element.textContent.trim().replace(/\s{2,}/g, ' ')
      };
    }).filter(item =>
      item.include && ((item.rect.right - item.rect.left) * (item.rect.bottom - item.rect.top) >= 20));
    
    // Only keep inner clickable items
    items = items.filter(x => !items.some(y => x.element.contains(y.element) && !(x == y)))
    
    // Lets create a floating border on top of these elements that will always be visible
    items.forEach(function(item) {
      newElement = document.createElement("div");
      newElement.style.outline = "2px dashed rgba(255,0,0,.75)";
      newElement.style.position = "absolute";
      newElement.style.left = item.rect.left + "px";
      newElement.style.top = item.rect.top + "px";
      newElement.style.width = (item.rect.right - item.rect.left) + "px";
      newElement.style.height = (item.rect.bottom - item.rect.top) + "px";
      newElement.style.pointerEvents = "none";
      newElement.style.boxSizering = "border-box";
      newElement.style.zIndex = 2147483647;
      document.body.appendChild(newElement);
    })
    
    

    иногда ложно срабатывает но в целом рабочее:
    Screen Shot 2024-06-07 at 21.21.55.png

  • 0 Votes
    4 Posts
    680 Views
  • 0 Votes
    2 Posts
    342 Views
  • 0 Votes
    7 Posts
    694 Views
  • 0 Votes
    7 Posts
    943 Views
  • 0 Votes
    33 Posts
    4916 Views