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

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

Ответы

Ответ 1

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

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

Ответ 2

Этот ответ в Vanilla:

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

Ответ 3

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

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

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

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

Ответ 4

Вот мое чистое решение 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: Обновлено для обработки при прокрутке вне экрана над экраном.

Ответ 5

Плагин jQuery Waypoints здесь очень приятный.

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

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

Ответ 6

Как насчет

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

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

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

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

Ответ 7

Использование ("нового") API IntersectionObserver

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

Ответ 8

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

$(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();
    });
};

Ответ 9

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

function isScrolledIntoView(elem)
{
    var docViewTop = $(window).scrollTop();
    var docViewBottom = docViewTop + $(window).height();
    var elemTop = $(elem).offset().top;
    return ((elemTop <= docViewBottom) && (elemTop >= docViewTop));
}

Ответ 10

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

Ответ 11

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

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

:

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

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

Ответ 12

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

Ответ 13

Существует плагин для 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/) от парня по имени Джеймс

Ответ 14

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

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

Ответ 15

Мне нужно было проверить видимость элементов внутри прокручиваемого контейнера 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);
    }

Ответ 16

Вот еще одно решение от 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

Ответ 17

Обычная ваниль, чтобы проверить, является ли элемент (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);

Ответ 18

Вы можете использовать плагин 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;
}

Ответ 19

Создание этого отличного ответа, вы можете немного упростить его с помощью 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

Ответ 20

У меня такой метод в моем приложении, но он не использует 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));
}

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

Ответ 21

Если вы хотите настроить его для прокрутки в другом 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)); 
}

Ответ 22

Изменен принятый ответ, чтобы элемент должен был отображать свойство, отличное от "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);
}

Ответ 23

Вот способ добиться того же, используя 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);
}});

Ответ 24

Пример, основанный на этом ответе, чтобы проверить, является ли элемент видимым на 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;
}

Ответ 25

Этот метод вернет 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;
}

Ответ 26

Простая модификация для прокручиваемого 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.

Ответ 27

Я адаптировал это короткое расширение функции 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));
};

Ответ 28

Я предпочитаю использовать jQuery expr

jQuery.extend(jQuery.expr[':'], {  
    inview: function (elem) {
        var t = $(elem);
        var offset = t.offset();
        var win = $(window); 
        var winST = win.scrollTop();
        var elHeight = t.outerHeight(true);

        if ( offset.top > winST - elHeight && offset.top < winST + elHeight + win.height()) {
            return true;    
        }    
        return false;  
    }
});

чтобы вы могли использовать его таким образом

$(".my-elem:inview"); //returns only element that is in view
$(".my-elem").is(":inview"); //check if element is in view
$(".my-elem:inview").length; //check how many elements are in view

Вы можете легко добавить такой код внутри функции события scroll и т.д., чтобы проверять его каждый раз, когда пользователь будет прокручивать представление.

Ответ 29

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

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

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

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

Ответ 30

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

elm = элемент, который вы хотите проверить, находится в представлении

scrollElement = вы можете передать окно или родительский элемент со списком

offset = если вы хотите, чтобы он срабатывал, когда элемент находился на расстоянии 200 пикселей до его отображения на экране, а затем передайте 200

function isScrolledIntoView(elem, scrollElement, offset)
        {
            var $elem = $(elem);
            var $window = $(scrollElement);
            var docViewTop = $window.scrollTop();
            var docViewBottom = docViewTop + $window.height();
            var elemTop = $elem.offset().top;
            var elemBottom = elemTop + $elem.height();
            
            return (((elemBottom+offset) >= docViewBottom) && ((elemTop-offset) <= docViewTop)) || (((elemBottom-offset) <= docViewBottom) && ((elemTop+offset) >= docViewTop));
        }