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

967

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

  • 0
    Я действительно не понимаю проблемы. Не могли бы вы попытаться добавить больше информации?
  • 38
    он означает, что он хочет, чтобы метод знал, отображается ли данный элемент в окне браузера, или пользователю нужно прокрутить, чтобы увидеть его.
Показать ещё 7 комментариев
Теги:
scroll

39 ответов

1220
Лучший ответ

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

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');
}
  • 45
    Обратите внимание, что это работает только в том случае, если документ является прокручиваемым элементом, т.е. вы не проверяете видимость какого-либо элемента внутри прокручиваемой внутренней панели.
  • 7
    как добавить немного смещения?
Показать ещё 15 комментариев
309

Этот ответ в 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;
}
  • 25
    не должно ли это быть isVisible = elementTop < window.innerHeight && elementBottom >= 0 ? В противном случае половина элемента на экране возвращает false.
  • 6
    нет. Я проверяю, полностью ли виден какой-либо элемент на странице. если вы хотите проверить видимость какой-либо части - вы можете настроить этот фрагмент.
Показать ещё 11 комментариев
111

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

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

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

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

  • 27
    Это отличный плагин, без сомнения, но не отвечает на вопрос.
  • 5
    Несмотря на то, что плагин jQuery-visible подходит для контента в области главной страницы, он, к сожалению, имеет проблемы с прокруткой div фиксированного размера с переполнением. Событие может сработать преждевременно, когда связанный элемент находится в видимой области страницы, но за пределами видимой области div, и затем не сработает, как ожидалось, когда элемент появляется в div.
Показать ещё 5 комментариев
70

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

  • 0
    спасибо, может быть лучше return top <= document.documentElement.clientHeight && top >= 0;
  • 13
    +1 Это был единственный закодированный (т.е. не сторонний) ответ, который учитывает рекурсивную природу элементов. Я расширен для обработки горизонтальной, вертикальной и прокрутки страницы: jsfiddle.net/9nuqpgqa
Показать ещё 6 комментариев
43

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

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

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

  • 3
    Для меня это работало только со смещением $('#my-div').waypoint(function() { console.log('Hello there!'); }, { offset: '100%' });
19

Как насчет

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

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

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

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

  • 1
    Это работает для меня, но я использовал, казалось бы, более полную, функцию isScrolledIntoView на stackoverflow.com/questions/487073/… :)
  • 3
    Я думаю, что это должно быть $ (window) .scrollTop () <$ (elem) .offset (). Top + $ (elem) .height ();
Показать ещё 1 комментарий
15

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

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

Использование ("новый") 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);

// provice 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)

  • 1
    Спасибо! Это работает для меня и также работает в IE11 с github.com/w3c/IntersectionObserver
  • 0
    Безусловно, лучшее решение. Работал в IE11 без полифилла!
Показать ещё 3 комментария
7

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

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

:

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

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

6

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

  • 0
    Спасибо за этот код. Интересно, как бы вы добавили прослушиватель событий при прокрутке, если у вас есть несколько вложенных прокручиваемых элементов? Кажется, что добавления прослушивателя к одному окну недостаточно, нужно ли возвращаться к верхнему родительскому элементу, чтобы добавить прослушиватель в каждый прокручиваемый контейнер?
  • 0
    @ mr1031011 Должна быть возможность добавить обработчик в окно, а затем проверить цель, чтобы идентифицировать контейнер, который был прокручен.
Показать ещё 2 комментария
6

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

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
6

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

  • 0
    Увы, jQuery inview больше не поддерживается и не работает с текущими версиями jQuery.
  • 0
    гм ... у меня работает на 1.11.1 которая является текущей версией
Показать ещё 2 комментария
6
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));
}
5

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

  • 1
    лучшее решение для меня, пока. делает работу очень хорошо и просто.
  • 0
    выдающийся !!! посмотрим, как я могу использовать это как его гораздо лучше, чем все, что я видел
4

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

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

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

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

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

Мне нужно было проверить видимость элементов внутри прокручиваемого контейнера 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);
    }
  • 0
    это работает для меня, если я изменяю e.style.opacity > 0 на (!e.style.opacity || e.style.opacity > 0) потому что по умолчанию это пустая строка для меня в FF.
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

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

  • 2
    По какой-то причине document.body.scrollTop всегда возвращает 0 (на ff3). Измените его на var visibleTop = (document.documentElement.scrollTop? Document.documentElement.scrollTop: document.body.scrollTop);
  • 0
    Простите за это. Мое приложение должно работать только в IE 6 (да, мне не повезло :(), поэтому я никогда не проверял это в FF ...
Показать ещё 1 комментарий
2

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

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

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

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

  • 0
    Использование expr для проверки видимости прокрутки элемента имеет огромный недостаток, поскольку он может работать только для элементов, которые не находятся внутри самих контейнеров прокрутки, поскольку вы используете объект window в качестве жестко заданной области видимости.
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

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

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

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

 /**
 * 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

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

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

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

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

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

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

1

Я просто хотел поделиться тем, что я объединил это с моим script, чтобы переместить 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

Мы можем сделать что-то подобное в современных браузерах, используя 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

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

    $.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');

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

0

Проверяет, присутствует ли элемент на экране вообще, а не принятый подход ответа, который проверяет, находится ли 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

Единственный плагин, который работает для меня последовательно для этого, заключается в следующем: 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;
}
-1

После непродолжительной работы и использования нескольких кодов, которые не сработали. Это то, что сработало для меня по вертикальной видимости прокрутки с помощью 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');

    }
-1

Только для 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
    Откуда getBoundingClientRect ?

Ещё вопросы

Сообщество Overcoder
Наверх
Меню