Как проверить, виден ли элемент после прокрутки? - PullRequest
1061 голосов
/ 28 января 2009

Я загружаю элементы через AJAX. Некоторые из них видны только при прокрутке страницы вниз.
Могу ли я узнать, находится ли элемент в видимой части страницы?

Ответы [ 39 ]

2 голосов
/ 26 сентября 2016

Существует более 30 ответов на этот вопрос, и ни один из них не использует удивительно простое, чистое решение JS, которое я использовал. Нет необходимости загружать jQuery только для того, чтобы решить эту проблему, как многие другие продвигают.

Чтобы определить, находится ли элемент в области просмотра, мы должны сначала определить положение элементов в теле. Нам не нужно делать это рекурсивно, как я когда-то думал. Вместо этого мы можем использовать element.getBoundingClientRect().

pos = elem.getBoundingClientRect().top - document.body.getBoundingClientRect().top;

Это значение представляет собой разницу Y между вершиной объекта и вершиной тела.

Затем мы должны сказать, находится ли элемент в поле зрения. Большинство реализаций спрашивают, находится ли полный элемент в области просмотра, поэтому это то, что мы рассмотрим.

Прежде всего, верхняя позиция окна: window.scrollY.

Мы можем получить нижнюю позицию окна, добавив высоту окна к его верхней позиции:

var window_bottom_position = window.scrollY + window.innerHeight;

Давайте создадим простую функцию для получения верхней позиции элемента:

function getElementWindowTop(elem){
    return elem && typeof elem.getBoundingClientRect === 'function' ? elem.getBoundingClientRect().top - document.body.getBoundingClientRect().top : 0;
}

Эта функция вернет верхнюю позицию элемента в окне или вернет 0, если вы передадите ему что-то отличное от элемента с помощью метода .getBoundingClientRect(). Этот метод существует уже давно, поэтому вам не нужно беспокоиться о том, что ваш браузер не поддерживает его.

Теперь верхняя позиция нашего элемента:

var element_top_position = getElementWindowTop(element);

И или нижняя позиция элемента:

var element_bottom_position = element_top_position + element.clientHeight;

Теперь мы можем определить, находится ли элемент в области просмотра, проверяя, находится ли нижняя позиция элемента ниже верхней позиции области просмотра, и проверяя, находится ли верхняя позиция элемента выше нижней позиции области просмотра:

if(element_bottom_position >= window.scrollY 
&& element_top_position <= window_bottom_position){
    //element is in view
else
    //element is not in view

Оттуда вы можете выполнить логику, чтобы добавить или удалить класс in-view для вашего элемента, который вы затем сможете обрабатывать позже с помощью эффектов перехода в вашем CSS.

Я абсолютно удивлен, что я не нашел этого решения нигде, но я верю, что это самое чистое и эффективное решение, и оно не требует загрузки jQuery!

1 голос
/ 12 сентября 2017

Более эффективная версия этого ответа :

 /**
 * Is element within visible region of a scrollable container
 * @param {HTMLElement} el - element to test
 * @returns {boolean} true if within visible region, otherwise false
 */
 function isScrolledIntoView(el) {
      var rect = el.getBoundingClientRect();
      return (rect.top >= 0) && (rect.bottom <= window.innerHeight);
 }
1 голос
/ 14 марта 2013

Я просто хотел поделиться, что я объединил это со своим скриптом, чтобы переместить div так, чтобы он всегда оставался на виду:

    $("#accordion").on('click', '.subLink', function(){
        var url = $(this).attr('src');
        updateFrame(url);
        scrollIntoView();
    });

    $(window).scroll(function(){
            changePos();
    });

  function scrollIntoView()
  {
        var docViewTop = $(window).scrollTop();
        var docViewBottom = docViewTop + $(window).height();    
        var elemTop = $("#divPos").offset().top;
        var elemBottom = elemTop + $("#divPos").height();               
        if (elemTop < docViewTop){
            $("#divPos").offset({top:docViewTop});
        }
   }

   function changePos(){        
    var scrTop = $(window).scrollTop();
    var frmHeight = $("#divPos").height()
        if ((scrTop < 200) || (frmHeight > 800)){   
         $("#divPos").attr("style","position:absolute;");
        }else{
          $("#divPos").attr("style","position:fixed;top:5px;");
        }
    }
0 голосов
/ 31 января 2019

Мы можем сделать что-то подобное в современных браузерах, используя ES6 :

const isFullySeen = el => el &&
  typeof el.getBoundingClientRect === 'function' &&
  el.getBoundingClientRect()['bottom'] + window.scrollY <= 
    window.innerHeight + window.scrollY && 
  el.getBoundingClientRect()['top'] + window.scrollY <= 
    window.innerHeight + window.scrollY;
0 голосов
/ 21 августа 2017

После непродуктивного бегания и использования нескольких кодов, которые не работали. Это то, что сработало для меня при вертикальной прокрутке с использованием Jquery. Замените '#footerplace' на элемент, который вы хотите отслеживать вертикально.

jQuery.expr.filters.offscreen = function(el) {
  var rect = el.getBoundingClientRect();
  console.log(rect)
  console.log('window height', $(window).height());

  return (
           (rect.top <= $(window).height()) && (rect.bottom <= $(window).height())
         );
};
$(document).scroll(function(){
    if ($('#footerplace').is(':offscreen')){
      console.log('this is true');
    $('#footerplace').is(':offscreen');
    } else {
     console.log('this is false');
    $('#footerplace').is(':offscreen');

    }
0 голосов
/ 30 мая 2017

Только Javascript:)

function isInViewport(element) {
  var rect = element.getBoundingClientRect();
  var html = document.documentElement;
  return (
    rect.top >= 0 &&
    rect.left >= 0 &&
    rect.bottom <= (window.innerHeight || html.clientHeight) &&
    rect.right <= (window.innerWidth || html.clientWidth)
  );
}
0 голосов
/ 18 апреля 2015

Единственный плагин, который постоянно работает для меня, это: https://github.com/customd/jquery-visible

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

public static boolean isVisible(Element e)
{
    //vp = viewPort, b = bottom, l = left, t = top, r = right
    int vpWidth   = Window.getClientWidth();
    int vpHeight = Window.getClientHeight();


    boolean tViz = ( e.getAbsoluteTop() >= 0 && e.getAbsoluteTop()<  vpHeight);
    boolean bViz = (e.getAbsoluteBottom() >  0 && e.getAbsoluteBottom() <= vpHeight);
    boolean lViz = (e.getAbsoluteLeft() >= 0 && e.getAbsoluteLeft() < vpWidth);
    boolean rViz = (e.getAbsoluteRight()  >  0 && e.getAbsoluteRight()  <= vpWidth);

    boolean vVisible   = tViz && bViz;
    boolean hVisible   = lViz && rViz;

    return hVisible && vVisible;
}
0 голосов
/ 05 мая 2015

Проверяет, находится ли элемент на экране вообще, а не принятым подходом ответа, который проверяет, находится ли div полностью на экране (что не сработает, если div больше экрана). В чистом JavaScript:

/**
 * Checks if element is on the screen (Y axis only), returning true
 * even if the element is only partially on screen.
 *
 * @param element
 * @returns {boolean}
 */
function isOnScreenY(element) {
    var screen_top_position = window.scrollY;
    var screen_bottom_position = screen_top_position + window.innerHeight;

    var element_top_position = element.offsetTop;
    var element_bottom_position = element_top_position + element.offsetHeight;

    return (inRange(element_top_position, screen_top_position, screen_bottom_position)
    || inRange(element_bottom_position, screen_top_position, screen_bottom_position));
}

/**
 * Checks if x is in range (in-between) the
 * value of a and b (in that order). Also returns true
 * if equal to either value.
 *
 * @param x
 * @param a
 * @param b
 * @returns {boolean}
 */
function inRange(x, a, b) {
    return (x >= a && x <= b);
}
0 голосов
/ 14 июня 2016

Сделан простой плагин, определяющий видимость элемента внутри прокручиваемого контейнера

    $.fn.isVisible = function(){

      var win;
      if(!arguments[0])
      {
        console.error('Specify a target;');
        return false;
      }
      else
      {
        win = $(arguments[0]);
      }
      var viewport = {};
      var bounds = this.offset();
      bounds.right = bounds.left + this.outerWidth();
      bounds.bottom = bounds.top + this.outerHeight();
      viewport.bottom = win.height() + win.offset().top;
      return (!( bounds.top > viewport.bottom) && (win.offset().top < bounds.bottom));
    };

Назовите это так $('elem_to_check').isVisible('scrollable_container');

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...