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

1170

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

yoavf
источник
42
он означает, что он хочет, чтобы метод знал, отображается ли данный элемент в окне браузера, или пользователю нужно прокрутить, чтобы увидеть его.
Ромен Линсолас
1
Чтобы проверить, является ли элемент полностью видимым в контейнере, просто добавьте дополнительный параметр селектора и повторно используйте для него код elem. Library.IsElementVisibleInContainer = function (elementSelector, containerSelector) { var containerViewTop = $(containerSelector).offset().top; var containerViewBottom = containerViewTop + $(containerSelector).height();
Жизнь
4
Возможный дубликат Как узнать, видим ли элемент DOM в текущем окне просмотра?
Аудрюс Мескаускас
1
Все ответы будут инициировать перекомпоновку, так что это может быть бутылочное горлышко, вы должны использовать IntersectionObserver, если поддерживается. Это будет иметь лучшую производительность в современных браузерах,
Jcubic

Ответы:

1259

Это должно сделать трюк:

function isScrolledIntoView(elem)
{
    var docViewTop = $(window).scrollTop();
    var docViewBottom = docViewTop + $(window).height();

    var elemTop = $(elem).offset().top;
    var elemBottom = elemTop + $(elem).height();

    return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
}

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

function Utils() {

}

Utils.prototype = {
    constructor: Utils,
    isElementInView: function (element, fullyInView) {
        var pageTop = $(window).scrollTop();
        var pageBottom = pageTop + $(window).height();
        var elementTop = $(element).offset().top;
        var elementBottom = elementTop + $(element).height();

        if (fullyInView === true) {
            return ((pageTop < elementTop) && (pageBottom > elementBottom));
        } else {
            return ((elementTop <= pageBottom) && (elementBottom >= pageTop));
        }
    }
};

var Utils = new Utils();

Применение

var isElementInView = Utils.isElementInView($('#flyout-left-container'), false);

if (isElementInView) {
    console.log('in view');
} else {
    console.log('out of view');
}
Скотт Доудинг
источник
52
Обратите внимание, что это работает, только если документ является прокручиваемым элементом, т.е. вы не проверяете видимость какого-либо элемента внутри прокручиваемой внутренней панели.
Андрей Б.
8
как добавить немного смещения?
Юрген Паул
5
Работал только тогда, когда я использовал window.innerHeightвместо этого
Кристиан Шнорр
2
Ибо elemTopя использовал $(elem).position().topи elemBottomя использовал elemTop + $(elem).outerHeight(true).
Сара Весселс
13
Для: «Любой части видимого элемента» я использовал: (((elemTop> = docViewTop) && (elemTop <= docViewBottom)) || ((elemBottom> = docViewTop) && (elemBottom <= docViewBottom))
Grizly
415

Этот ответ в ванили:

function isScrolledIntoView(el) {
    var rect = el.getBoundingClientRect();
    var elemTop = rect.top;
    var elemBottom = rect.bottom;

    // Only completely visible elements return true:
    var isVisible = (elemTop >= 0) && (elemBottom <= window.innerHeight);
    // Partially visible elements return true:
    //isVisible = elemTop < window.innerHeight && elemBottom >= 0;
    return isVisible;
}
bravedick
источник
27
не должно ли это быть isVisible = elementTop < window.innerHeight && elementBottom >= 0? В противном случае половина элемента на экране возвращает false.
мужчина
7
нет. Я проверяю, полностью ли виден какой-либо элемент на странице. если вы хотите проверить видимость какой-либо части - вы можете настроить этот фрагмент.
Bravedick
15
Я считаю этот ответ лучше, чем выбранный ответ. Проще тоже.
Адам Венеция
12
По сравнению с утвержденным ответом, это работает намного лучше с сотнями элементов.
НКЛ
5
увидеть небольшую скрипку, демонстрирующую здесь - jsfiddle.net/shaaraddalvi/4rp09jL0
upInCloud
122

Обновление: используйте IntersectionObserver


Лучший метод, который я нашел на данный момент, - это плагин jQuery . Работает как шарм.

Имитирует пользовательское событие «появиться», которое срабатывает, когда элемент прокручивается в поле зрения или иным образом становится видимым для пользователя.

$('#foo').appear(function() {
  $(this).text('Hello world');
});

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

Джо Ленсиони
источник
30
Это отличный плагин, без сомнения, но не отвечает на вопрос.
Джон Адамс
5
Хотя плагин jQuery-visible удобен для контента в области главной страницы, он, к сожалению, имеет проблемы с прокруткой div фиксированного размера с переполнением. Событие может сработать преждевременно, когда связанный элемент находится в видимой области страницы, но за пределами видимой области div, и затем не сработает, как ожидалось, когда элемент появляется в div.
Питер
17
Есть ли исчезающий плагин?
Shamoon
3
@Shamoon проверьте источник для, appear pluginи вам, вероятно, просто нужно добавить !куда-нибудь, чтобы получить disappearплагин.
Lucky Soni
5
Как примечание, это не работает с jQuery 1.11.X github.com/morr/jquery.appear/issues/37
Джейсон Пархем
86

Вот мое чистое решение JavaScript, которое работает, если оно также скрыто внутри прокручиваемого контейнера.

Демо здесь (попробуйте изменить размер окна тоже)

var visibleY = function(el){
  var rect = el.getBoundingClientRect(), top = rect.top, height = rect.height, 
    el = el.parentNode
  // Check if bottom of the element is off the page
  if (rect.bottom < 0) return false
  // Check its within the document viewport
  if (top > document.documentElement.clientHeight) return false
  do {
    rect = el.getBoundingClientRect()
    if (top <= rect.bottom === false) return false
    // Check if the element is out of view due to a container scrolling
    if ((top + height) <= rect.top) return false
    el = el.parentNode
  } while (el != document.body)
  return true
};

РЕДАКТИРОВАТЬ 2016-03-26: Я обновил решение для учета прокрутки мимо элемента, чтобы он скрывался над верхней частью контейнера с возможностью прокрутки. РЕДАКТИРОВАТЬ 2018-10-08: Обновлено для обработки при прокрутке вне экрана над экраном.

союзник
источник
спасибо, может быть, лучше return top <= document.documentElement.clientHeight && top >= 0;
Юсеф Салимпур
16
+1 Это был единственный закодированный (т.е. не сторонний) ответ, который учитывает рекурсивную природу элементов. Я расширен для обработки горизонтальной, вертикальной прокрутки и прокрутки страницы: jsfiddle.net/9nuqpgqa
Pebbl
3
Это решение проверяет только верхнюю часть элемента. Если первый верхний пиксель виден, он вернет true, даже если остальная часть элемента не видна. Чтобы проверить, виден ли весь элемент, нужно также проверить свойство bottom.
Войцех Якубас
2
Да, аккуратно! Используется, чтобы помочь написать этот ответ (с пометкой как комментарий js).
Roamer-1888
Отсутствует ; после второго «возврата ложного» в петлю
Михаил Рамендик
46

Использование IntersectionObserver API (встроено в современные браузеры)

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

Отпадает необходимость в прикреплении scrollсобытия и ручной проверке обратного вызова, что повышает эффективность:

// this is the target which is observed
var target = document.querySelector('div');

// configure the intersection observer instance
var intersectionObserverOptions = {
  root: null,
  rootMargin: '150px',
  threshold: 1.0
}
    
var observer = new IntersectionObserver(onIntersection, intersectionObserverOptions);

// provide the observer with a target
observer.observe(target);

function onIntersection(entries){
  entries.forEach(entry => {
    console.clear();
    console.log(entry.intersectionRatio)
    target.classList.toggle('visible', entry.intersectionRatio > 0);
    
    // Are we in viewport?
    if (entry.intersectionRatio > 0) {
      // Stop watching 
      // observer.unobserve(entry.target);
    }
  });
}
.box{ width:100px; height:100px; background:red; margin:1000px; }
.box.visible{ background:green; }
Scroll both Vertically & Horizontally...
<div class='box'></div>


Просмотр таблицы поддержки браузеров (не поддерживается в IE / Safari)

VSync
источник
4
Спасибо! Это работает для меня, а также заставило его работать в IE11 с github.com/w3c/IntersectionObserver
Мэтт Уилсон
Безусловно, лучшее решение. Работал в IE11 без полифилла!
Фабиан фон Эллертс
Обратите внимание, что это все еще не поддерживается в iOS / macOS Safari, к сожалению. Обязательно проверяйте проблемы с перфорированием, если вы выбираете polyfill, это большая группа пользователей
Leland
@Leland - это зависит от проекта. для всех моих проектов это абсолютная группа 0 пользователей. Я не создаю сайты, но веб-систему;)
vsync
я пытаюсь запустить это в цикле на нескольких элементах, но это не работает. Любые идеи? Я добавляю элемент к цели в этом цикле.
Саша Гриндау
42

Плагин jQuery Waypoints идет очень хорошо здесь.

$('.entry').waypoint(function() {
   alert('You have scrolled to an entry.');
});

На сайте плагина есть несколько примеров .

Федир РЫХТИК
источник
3
Для меня это работало только со смещением $('#my-div').waypoint(function() { console.log('Hello there!'); }, { offset: '100%' });
leymannx
21

Как насчет

function isInView(elem){
   return $(elem).offset().top - $(window).scrollTop() < $(elem).height() ;
}

После этого вы можете запускать все, что захотите, когда элемент будет виден вот так

$(window).scroll(function(){
   if (isInView($('.classOfDivToCheck')))
      //fire whatever you what 
      dothis();
})

Это работает для меня просто отлично

webicy
источник
1
Это работает для меня, но я использовал, по-видимому, более полную функцию isScrolledIntoView на stackoverflow.com/questions/487073/… :)
Meetai.com
3
Я думаю, что это должно быть $ (window) .scrollTop () <$ (elem) .offset (). Top + $ (elem) .height ();
Янг
Моя модификация будет выглядеть так: `return $ (window) .scrollTop () + $ (window) .height ()> $ (elem) .offset (). Top + $ (elem) .height (); `
бубенкод
16

Крутая функция Скотта Даудинга для моих требований - она ​​используется для определения, прокручивается ли элемент на экране, т.е. его верхний край.

function isScrolledIntoView(elem)
{
    var docViewTop = $(window).scrollTop();
    var docViewBottom = docViewTop + $(window).height();
    var elemTop = $(elem).offset().top;
    return ((elemTop <= docViewBottom) && (elemTop >= docViewTop));
}
Снигдха Батра
источник
15

WebResourcesDepot написал скрипт для загрузки при прокрутке, который некоторое время назад использовал jQuery . Вы можете посмотреть их Live Demo здесь . Основой их функциональности было следующее:

$(window).scroll(function(){
  if  ($(window).scrollTop() == $(document).height() - $(window).height()){
    lastAddedLiveFunc();
  }
});

function lastAddedLiveFunc() { 
  $('div#lastPostsLoader').html('<img src="images/bigLoader.gif">');
  $.post("default.asp?action=getLastPosts&lastPostID="+$(".wrdLatest:last").attr("id"),
    function(data){
        if (data != "") {
          $(".wrdLatest:last").after(data);         
        }
      $('div#lastPostsLoader').empty();
    });
};
Сэмпсон
источник
12

Простая ваниль, чтобы проверить, elвидим ли элемент ( ) в прокручиваемом div ( holder)

function isElementVisible (el, holder) {
  holder = holder || document.body
  const { top, bottom, height } = el.getBoundingClientRect()
  const holderRect = holder.getBoundingClientRect()

  return top <= holderRect.top
    ? holderRect.top - top <= height
    : bottom - holderRect.bottom <= height
},

Использование с JQuery:

var el = $('tr:last').get(0);
var holder = $('table').get(0);
isVisible =  isScrolledIntoView(el, holder);
Денис Матафонов
источник
2
В эту эпоху одностраничных приложений стало более привычным проверять, видим ли элемент в каком-либо другом элементе, кроме окна . Вот почему этот получает мой голос.
H Dog
8

isScrolledIntoView - очень нужная функция, поэтому я попробовал ее, она работает для элементов, которые не выше, чем область просмотра, но если элемент больше, чем область просмотра, он не работает. Чтобы исправить это легко изменить условие

return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));

к этому:

return (docViewBottom >= elemTop && docViewTop <= elemBottom);

Смотрите демо здесь: http://jsfiddle.net/RRSmQ/

Роберт
источник
8

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

Чтобы покрыть эту возможность, вы должны проверить, находится ли элемент в границах каждого из его родителей.

Это решение делает именно это:

function(element, percentX, percentY){
    var tolerance = 0.01;   //needed because the rects returned by getBoundingClientRect provide the position up to 10 decimals
    if(percentX == null){
        percentX = 100;
    }
    if(percentY == null){
        percentY = 100;
    }

    var elementRect = element.getBoundingClientRect();
    var parentRects = [];

    while(element.parentElement != null){
        parentRects.push(element.parentElement.getBoundingClientRect());
        element = element.parentElement;
    }

    var visibleInAllParents = parentRects.every(function(parentRect){
        var visiblePixelX = Math.min(elementRect.right, parentRect.right) - Math.max(elementRect.left, parentRect.left);
        var visiblePixelY = Math.min(elementRect.bottom, parentRect.bottom) - Math.max(elementRect.top, parentRect.top);
        var visiblePercentageX = visiblePixelX / elementRect.width * 100;
        var visiblePercentageY = visiblePixelY / elementRect.height * 100;
        return visiblePercentageX + tolerance > percentX && visiblePercentageY + tolerance > percentY;
    });
    return visibleInAllParents;
};

Он также позволяет указать, какой процент должен быть виден в каждом направлении.
Это не покрывает вероятность того, что это может быть скрыто из-за других факторов, таких как display: hidden.

Это должно работать во всех основных браузерах, так как используется только getBoundingClientRect. Я лично проверил это в Chrome и Internet Explorer 11.

Domysee
источник
Спасибо за этот код. Интересно, как бы вы добавили прослушиватель событий при прокрутке, если у вас есть несколько вложенных прокручиваемых элементов? Кажется, что добавления прослушивателя к одному окну недостаточно, нужно ли возвращаться к верхнему родительскому элементу, чтобы добавить прослушиватель в каждый прокручиваемый контейнер?
mr1031011
@ mr1031011 Должна быть возможность добавить обработчик в окно, а затем проверить цель, чтобы идентифицировать контейнер, который был прокручен.
Domysee
верно, это не работает с примером, данным @vanowm,
mr1031011
7
function isScrolledIntoView(elem) {
    var docViewTop = $(window).scrollTop(),
        docViewBottom = docViewTop + $(window).height(),
        elemTop = $(elem).offset().top,
     elemBottom = elemTop + $(elem).height();
   //Is more than half of the element visible
   return ((elemTop + ((elemBottom - elemTop)/2)) >= docViewTop && ((elemTop + ((elemBottom - elemTop)/2)) <= docViewBottom));
}
Паскаль Ганье
источник
7

Вот еще одно решение от http://web-profile.com.ua/

<script type="text/javascript">
$.fn.is_on_screen = function(){
    var win = $(window);
    var viewport = {
        top : win.scrollTop(),
        left : win.scrollLeft()
    };
    viewport.right = viewport.left + win.width();
    viewport.bottom = viewport.top + win.height();

    var bounds = this.offset();
    bounds.right = bounds.left + this.outerWidth();
    bounds.bottom = bounds.top + this.outerHeight();

    return (!(viewport.right < bounds.left || viewport.left > bounds.right ||    viewport.bottom < bounds.top || viewport.top > bounds.bottom));
 };

if( $('.target').length > 0 ) { // if target element exists in DOM
    if( $('.target').is_on_screen() ) { // if target element is visible on screen after DOM loaded
        $('.log').html('<div class="alert alert-success">target element is visible on screen</div>'); // log info       
    } else {
        $('.log').html('<div class="alert">target element is not visible on screen</div>'); // log info
    }
}
$(window).scroll(function(){ // bind window scroll event
if( $('.target').length > 0 ) { // if target element exists in DOM
    if( $('.target').is_on_screen() ) { // if target element is visible on screen after DOM loaded
        $('.log').html('<div class="alert alert-success">target element is visible on screen</div>'); // log info
    } else {
        $('.log').html('<div class="alert">target element is not visible on screen</div>'); // log info
    }
}
});
</script>

Смотрите это в JSFiddle

Адриан П.
источник
7

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

function inViewport($ele) {
    var lBound = $(window).scrollTop(),
        uBound = lBound + $(window).height(),
        top = $ele.offset().top,
        bottom = top + $ele.outerHeight(true);

    return (top > lBound && top < uBound)
        || (bottom > lBound && bottom < uBound)
        || (lBound >= top && lBound <= bottom)
        || (uBound >= top && uBound <= bottom);
}

Чтобы назвать это используйте что-то вроде этого:

var $myElement = $('#my-element'),
    canUserSeeIt = inViewport($myElement);

console.log(canUserSeeIt); // true, if element is visible; false otherwise
Брент Барбата
источник
7

Для jQuery есть плагин inview, который добавляет новое событие inview.


Вот некоторый код для плагина jQuery, который не использует события:

$.extend($.expr[':'],{
    inView: function(a) {
        var st = (document.documentElement.scrollTop || document.body.scrollTop),
            ot = $(a).offset().top,
            wh = (window.innerHeight && window.innerHeight < $(window).height()) ? window.innerHeight : $(window).height();
        return ot > st && ($(a).height() + ot) < (st + wh);
    }
});

(function( $ ) {
    $.fn.inView = function() {
        var st = (document.documentElement.scrollTop || document.body.scrollTop),
        ot = $(this).offset().top,
        wh = (window.innerHeight && window.innerHeight < $(window).height()) ? window.innerHeight : $(window).height();

        return ot > st && ($(this).height() + ot) < (st + wh);
    };
})( jQuery );

Я нашел это в комментарии здесь ( http://remysharp.com/2009/01/26/element-in-view-event-plugin/ ) парнем по имени Джеймс

Несс-EE
источник
Увы, jQuery inview больше не поддерживается и не работает с текущими версиями jQuery.
mikemaccana
1
JQuery 1 для поддержки старых браузеров, новые функции в jQuery 2.
mikemaccana
Ссылка не показывает пример, поскольку страница была обновлена.
профессор программирования
6

Мне нужно было проверить видимость элементов внутри прокручиваемого DIV контейнера.

    //p = DIV container scrollable
    //e = element
    function visible_in_container(p, e) {
        var z = p.getBoundingClientRect();
        var r = e.getBoundingClientRect();

        // Check style visiblilty and off-limits
        return e.style.opacity > 0 && e.style.display !== 'none' &&
               e.style.visibility !== 'hidden' &&
               !(r.top > z.bottom || r.bottom < z.top ||
                 r.left > z.right || r.right < z.left);
    }
Пигмалион
источник
это работает для меня , если я изменю e.style.opacity > 0в (!e.style.opacity || e.style.opacity > 0)потому , что по умолчанию это пустая строка для меня в FF.
Бретт Замир
6

Основываясь на этом великолепном ответе , вы можете немного упростить его, используя ES2015 +:

function isScrolledIntoView(el) {
  const { top, bottom } = el.getBoundingClientRect()
  return top >= 0 && bottom <= window.innerHeight
}

Если вы не заботитесь о том, чтобы верх выходил из окна, и просто заботились о том, чтобы нижняя часть была просмотрена, это можно упростить до

function isSeen(el) {
  return el.getBoundingClientRect().bottom <= window.innerHeight
}

или даже однострочник

const isSeen = el => el.getBoundingClientRect().bottom <= window.innerHeight
rpearce
источник
4

Вы можете использовать плагин jquery "onScreen", чтобы проверить, находится ли элемент в текущем окне просмотра при прокрутке. Плагин устанавливает «: onScreen» селектора в true, когда селектор появляется на экране. Это ссылка на плагин, который вы можете включить в свой проект. " http://benpickles.github.io/onScreen/jquery.onscreen.min.js "

Вы можете попробовать приведенный ниже пример, который работает для меня.

$(document).scroll(function() {
    if($("#div2").is(':onScreen')) {
        console.log("Element appeared on Screen");
        //do all your stuffs here when element is visible.
    }
    else {
        console.log("Element not on Screen");
        //do all your stuffs here when element is not visible.
    }
});

HTML-код:

<div id="div1" style="width: 400px; height: 1000px; padding-top: 20px; position: relative; top: 45px"></div> <br>
<hr /> <br>
<div id="div2" style="width: 400px; height: 200px"></div>

CSS:

#div1 {
    background-color: red;
}
#div2 {
    background-color: green;
}
Васуки Дилип
источник
3

У меня есть такой метод в моем приложении, но он не использует jQuery:

/* Get the TOP position of a given element. */
function getPositionTop(element){
    var offset = 0;
    while(element) {
        offset += element["offsetTop"];
        element = element.offsetParent;
    }
    return offset;
}

/* Is a given element is visible or not? */
function isElementVisible(eltId) {
    var elt = document.getElementById(eltId);
    if (!elt) {
        // Element not found.
        return false;
    }
    // Get the top and bottom position of the given element.
    var posTop = getPositionTop(elt);
    var posBottom = posTop + elt.offsetHeight;
    // Get the top and bottom position of the *visible* part of the window.
    var visibleTop = document.body.scrollTop;
    var visibleBottom = visibleTop + document.documentElement.offsetHeight;
    return ((posBottom >= visibleTop) && (posTop <= visibleBottom));
}

Изменить: Этот метод хорошо работает для IE (по крайней мере, версия 6). Прочитайте комментарии для совместимости с FF.

Ромэн Линсолас
источник
2
По какой-то причине document.body.scrollTop всегда возвращает 0 (на ff3). Измените его на var visibleTop = (document.documentElement.scrollTop? Document.documentElement.scrollTop: document.body.scrollTop);
yoavf
Простите за это. Мое приложение должно работать только в IE 6 (да, мне не повезло :(), поэтому я никогда не проверял это в FF ...
Romain Linsolas
Это был бы лучший ответ здесь, если бы он был правильным. Исправьте одну из своих строк: var visibleBottom = visibleTop + window.innerHeight;я не использую jQuery, и вы помогли мне найти правильный ответ.
Bitterblue
3

Если вы хотите настроить это для прокрутки элемента в другом div,

function isScrolledIntoView (elem, divID) 

{

    var docViewTop = $('#' + divID).scrollTop();


    var docViewBottom = docViewTop + $('#' + divID).height();

    var elemTop = $(elem).offset().top;
    var elemBottom = elemTop + $(elem).height();

    return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop)); 
}
Самия Ахтар
источник
3

Изменили принятый ответ, чтобы элементу было присвоено свойство display, отличное от «none», с качеством как видимым.

function isScrolledIntoView(elem) {
   var docViewTop = $(window).scrollTop();
  var docViewBottom = docViewTop + $(window).height();

  var elemTop = $(elem).offset().top;
  var elemBottom = elemTop + $(elem).height();
  var elemDisplayNotNone = $(elem).css("display") !== "none";

  return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop) && elemDisplayNotNone);
}
evanmcd
источник
3

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

Element.implement({
inVerticalView: function (full) {
    if (typeOf(full) === "null") {
        full = true;
    }

    if (this.getStyle('display') === 'none') {
        return false;
    }

    // Window Size and Scroll
    var windowScroll = window.getScroll();
    var windowSize = window.getSize();
    // Element Size and Scroll
    var elementPosition = this.getPosition();
    var elementSize = this.getSize();

    // Calculation Variables
    var docViewTop = windowScroll.y;
    var docViewBottom = docViewTop + windowSize.y;
    var elemTop = elementPosition.y;
    var elemBottom = elemTop + elementSize.y;

    if (full) {
        return ((elemBottom >= docViewTop) && (elemTop <= docViewBottom)
            && (elemBottom <= docViewBottom) && (elemTop >= docViewTop) );
    } else {
        return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
    }
},
inHorizontalView: function(full) {
    if (typeOf(full) === "null") {
        full = true;
    }

    if (this.getStyle('display') === 'none') {
        return false;
    }

    // Window Size and Scroll
    var windowScroll = window.getScroll();
    var windowSize = window.getSize();
    // Element Size and Scroll
    var elementPosition = this.getPosition();
    var elementSize = this.getSize();

    // Calculation Variables
    var docViewLeft = windowScroll.x;
    var docViewRight = docViewLeft + windowSize.x;
    var elemLeft = elementPosition.x;
    var elemRight = elemLeft + elementSize.x;

    if (full) {
        return ((elemRight >= docViewLeft) && (elemLeft <= docViewRight)
            && (elemRight <= docViewRight) && (elemLeft >= docViewLeft) );
    } else {
        return ((elemRight <= docViewRight) && (elemLeft >= docViewLeft));
    }
},
inView: function(full) {
    return this.inHorizontalView(full) && this.inVerticalView(full);
}});
bmlkc
источник
3

Пример, основанный на этом ответе, проверяет, является ли элемент видимым на 75% (т.е. менее 25% его находится за пределами экрана).

function isScrolledIntoView(el) {
  // check for 75% visible
  var percentVisible = 0.75;
  var elemTop = el.getBoundingClientRect().top;
  var elemBottom = el.getBoundingClientRect().bottom;
  var elemHeight = el.getBoundingClientRect().height;
  var overhang = elemHeight * (1 - percentVisible);

  var isVisible = (elemTop >= -overhang) && (elemBottom <= window.innerHeight + overhang);
  return isVisible;
}
Брендан Ни
источник
3

На этот вопрос есть более 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!

WebWanderer
источник
Очень хорошее объяснение! Но уже есть ответы, которые делают именно то, что вы делаете, например , ответ Элли
Domysee
1
@ Domysee Хм, я как-то пропустил это. Справедливо. Спасибо, что указали на это, хотя. Приятно видеть, что это сделано по-другому.
WebWanderer
3

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

 /**
 * 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);
 }
Джон Доэрти
источник
2

Этот метод вернет true, если какая-либо часть элемента видна на странице. Это работало лучше в моем случае и может помочь кому-то еще.

function isOnScreen(element) {
  var elementOffsetTop = element.offset().top;
  var elementHeight = element.height();

  var screenScrollTop = $(window).scrollTop();
  var screenHeight = $(window).height();

  var scrollIsAboveElement = elementOffsetTop + elementHeight - screenScrollTop >= 0;
  var elementIsVisibleOnScreen = screenScrollTop + screenHeight - elementOffsetTop >= 0;

  return scrollIsAboveElement && elementIsVisibleOnScreen;
}
Рафаэль Гарсия
источник
2

Простая модификация прокручиваемого div (контейнера)

var isScrolledIntoView = function(elem, container) {
    var containerHeight = $(container).height();
    var elemTop = $(elem).position().top;
    var elemBottom = elemTop + $(elem).height();
    return (elemBottom > 0 && elemTop < containerHeight);
}

ПРИМЕЧАНИЕ: это не работает, если элемент больше прокручиваемого div.

Деррик Дж. Випплер
источник
2

Я адаптировал это короткое расширение функции jQuery, которое вы можете свободно использовать (лицензия MIT).

/**
 * returns true if an element is visible, with decent performance
 * @param [scope] scope of the render-window instance; default: window
 * @returns {boolean}
 */
jQuery.fn.isOnScreen = function(scope){
    var element = this;
    if(!element){
        return;
    }
    var target = $(element);
    if(target.is(':visible') == false){
        return false;
    }
    scope = $(scope || window);
    var top = scope.scrollTop();
    var bot = top + scope.height();
    var elTop = target.offset().top;
    var elBot = elTop + target.height();

    return ((elBot <= bot) && (elTop >= top));
};
Лоренц Ло Зауэр
источник
2

Я написал компонент для этой задачи, предназначенный для чрезвычайно быстрой обработки большого количества элементов (до 10 мс для 1000 элементов на медленном мобильном телефоне). ).

Он работает с каждым типом контейнера прокрутки, к которому у вас есть доступ - окном, элементами HTML, встроенным iframe, порожденным дочерним окном - и очень гибок в обнаружении ( полная или частичная видимость , поле границы или поле содержимого , настраиваемая зона допуска и т. Д. ).

Огромный, в основном автоматически сгенерированный набор тестов гарантирует, что он работает как рекламируемый кросс-браузерный .

Дайте ему шанс, если вам нравится: jQuery.isInView . В противном случае вы можете найти вдохновение в исходном коде, например, здесь .

hashchange
источник