如何在滚动后检查元素是否可见?

yoa*_*avf 1115 javascript jquery scroll

我正在通过AJAX加载元素.只有向下滚动页面时,其中一些才可见.
有什么方法我可以知道一个元素现在是否在页面的可见部分?

小智 1226

这应该做的伎俩:

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));
}
Run Code Online (Sandbox Code Playgroud)

简单实用程序功能 这将允许您调用一个实用程序函数,该函数接受您正在查找的元素,以及是否希望元素完全处于视图中或部分处于视图中.

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();
Run Code Online (Sandbox Code Playgroud)

用法

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

if (isElementInView) {
    console.log('in view');
} else {
    console.log('out of view');
}
Run Code Online (Sandbox Code Playgroud)

  • 请注意,这仅在文档是滚动元素时才有效,即您没有检查滚动内部窗格中某些元素的可见性. (47认同)
  • 对于:"视图中元素的任何部分",我使用:(((elemTop> = docViewTop)&&(elemTop <= docViewBottom))||((elemBottom> = docViewTop)&&(elemBottom <= docViewBottom))) (12认同)
  • 如何添加一点偏移量? (7认同)
  • 只有在我使用`window.innerHeight`时才有效 (5认同)
  • 对于`elemTop`,我使用`$(elem).position().top`和'elemBottom`我使用了'elemTop + $(elem).outerHeight(true)`. (2认同)
  • 另外,如果整个元素都在视图中,使用`&&`进行测试.如果您想知道元素的任何部分是否在视图中,请使用"||". (2认同)
  • 对于"视图中元素的任何部分",`((elemTop <= docViewBottom)&&(elemBottom> = docViewTop))`完全覆盖所有情况 - 即使顶部和底部边缘在屏幕外,只有中间在视图中. (2认同)

bra*_*ick 381

香草的答案:

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;
}
Run Code Online (Sandbox Code Playgroud)

  • 不应该是`isVisible = elementTop <window.innerHeight && elementBottom> = 0`?否则,屏幕上的元素一半返回false. (26认同)
  • 我发现这个答案比选择的答案表现得更好.也更简单. (14认同)
  • 与批准的答案相比,这可以使用数百个元素更好地执行. (11认同)
  • 没有.我检查一些元素是否在页面上完全可见.如果要检查某些部分的可见性 - 您可以自定义此代码段. (6认同)
  • 看到这里展示的小小提琴 - https://jsfiddle.net/shaaraddalvi/4rp09jL0/ (5认同)
  • 有没有什么特别的原因jQuery在SO上比vanilla更受青睐? (3认同)
  • 我将`el.getBoundingClientRect()`的结果缓存在一个变量中,而不是两次调用它来挤出一些免费的性能提升. (2认同)

Joe*_*oni 120

到目前为止我发现的最好的方法是jQuery出现的插件.奇迹般有效.

模仿自定义"出现"事件,当元素滚动到视图中或以其他方式对用户可见时触发.

$('#foo').appear(function() {
  $(this).text('Hello world');
});
Run Code Online (Sandbox Code Playgroud)

此插件可用于防止对隐藏或可视区域外的内容进行不必要的请求.

  • 毫无疑问,这是一个很酷的插件,但没有回答这个问题. (29认同)
  • 是否有一个消失的插件? (16认同)
  • 虽然jQuery-appear插件适用于主页面区域的内容,但遗憾的是它存在固定大小滚动div与溢出问题.当绑定元素位于页面的可查看区域内但在div的可视区域之外时,事件可能会过早触发,然后当元素进入div中时,不会按预期触发. (5认同)
  • 请注意,这不适用于jQuery 1.11.X https://github.com/morr/jquery.appear/issues/37 (5认同)
  • @Shamoon检查`now plugin`的源代码,你可能只需要在某处添加一个`!`来获得一个`disappear`插件. (3认同)

All*_*lly 80

这是我的纯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
};
Run Code Online (Sandbox Code Playgroud)

编辑2016-03-26:我已经更新了解决方案,以便滚动浏览元素,因此它隐藏在可滚动容器的顶部之上. 编辑2018-10-08:更新以在屏幕上方滚动视图时进行处理.

  • +1这是考虑到元素的递归性质的唯一编码(即非第三方)答案.我已经扩展到处理水平,垂直和页面滚动:http://jsfiddle.net/9nuqpgqa/ (14认同)
  • 此解决方案仅检查元素的顶部.如果第一个顶部像素可见,即使项目的其余部分不可见,它也会返回true.要检查整个元素是否可见,您还需要检查底部属性. (2认同)
  • 是的,整洁!用来帮助写[这个答案](http://stackoverflow.com/a/42246594/3478010)(作为js评论的信用). (2认同)

Fed*_*TIK 42

jQuery Waypoints插件在这里非常好用.

$('.entry').waypoint(function() {
   alert('You have scrolled to an entry.');
});
Run Code Online (Sandbox Code Playgroud)

插件网站上有一些例子.

  • 对我来说,它只能使用偏移量`$('#my-div').waypoint(function(){console.log('Hello there!');},{offset:'100%'});` (3认同)

vsy*_*ync 34

使用("new")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);
    }
  });
}
Run Code Online (Sandbox Code Playgroud)
.box{ width:100px; height:100px; background:red; margin:1000px; }
.box.visible{ background:green; }
Run Code Online (Sandbox Code Playgroud)
Scroll both Vertically & Horizontally...
<div class='box'></div>
Run Code Online (Sandbox Code Playgroud)


查看浏览器支持表(IE/Safari不支持)

  • Safari 是新的 IE,这些天我想要实现的一切都受到所有常青浏览器的支持......除了 safari (6认同)
  • 谢谢!这对我有用,也可以通过https://github.com/w3c/IntersectionObserver在IE11中使用 (2认同)

web*_*icy 20

How about

function isInView(elem){
   return $(elem).offset().top - $(window).scrollTop() < $(elem).height() ;
}
Run Code Online (Sandbox Code Playgroud)

After that you can trigger whatever you want once the element is in view like this

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

That works for me just fine

  • 我认为应该是$(window).scrollTop()<$(elem).offset().top + $(elem).height(); (3认同)

Sam*_*son 15

WebResourcesDepot了一个脚本,在滚动时加载,前一段时间使用jQuery.你可以在这里查看他们的现场演示.他们功能的牛肉是这样的:

$(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();
    });
};
Run Code Online (Sandbox Code Playgroud)


Sni*_*tra 14

根据我的要求推荐了Scott Dowding的酷功能 - 这用于查找元素是否刚刚滚动到屏幕中,即它的顶部边缘.

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


Man*_*mar 11

我找到的最简单的解决方案是Intersection Observer API

var observer = new IntersectionObserver(function(entries) {
    if(entries[0].isIntersecting === true)
        console.log('Element has just become visible in screen');
}, { threshold: [0] });

observer.observe(document.querySelector("#main-container"));
Run Code Online (Sandbox Code Playgroud)


Rob*_*ert 8

isScrolledIntoView是一个非常需要的函数,所以我尝试了它,它适用于不比视口更高的元素,但如果元素比视口更大则不起作用.要解决此问题,请轻松更改条件

return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
Run Code Online (Sandbox Code Playgroud)

对此:

return (docViewBottom >= elemTop && docViewTop <= elemBottom);
Run Code Online (Sandbox Code Playgroud)

请参阅此处的演示:http://jsfiddle.net/RRSmQ/


Dom*_*see 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;
};
Run Code Online (Sandbox Code Playgroud)

它还允许您指定在每个方向上可见的百分比.
它没有涵盖由于其他因素而可能隐藏的可能性,例如display: hidden.

这应该适用于所有主流浏览器,因为它只使用getBoundingClientRect.我亲自在Chrome和Internet Explorer 11中测试过它.


Den*_*nov 8

普通香草检查元素(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
},
Run Code Online (Sandbox Code Playgroud)

jQuery的用法:

var el = $('tr:last').get(0);
var holder = $('table').get(0);
isVisible =  isScrolledIntoView(el, holder);
Run Code Online (Sandbox Code Playgroud)

  • 在这个单页应用程序时代,检查一个元素在**窗口**之外的其他元素中是否可见已经变得更加常见。这就是为什么这个得到我的支持。 (4认同)
  • 注意:如果您希望基于元素的任何不可见部分(如我的情况)返回此值,请从函数中删除 height 变量并将其使用的位置更改为 0(零)。那么如果你只隐藏了元素的“部分”,它将返回 false。 (2认同)

Pas*_*eur 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));
}
Run Code Online (Sandbox Code Playgroud)


nes*_*-EE 7

有一个名为inview的 jQuery插件,它添加了一个新的"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 );
Run Code Online (Sandbox Code Playgroud)

我在这里发表评论(http://remysharp.com/2009/01/26/element-in-view-event-plugin/)


Adr*_* P. 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>
Run Code Online (Sandbox Code Playgroud)

JSFiddle中看到它

  • 到目前为止,对我来说最好的解决方案。做得很好,很简单。 (2认同)

Bre*_*ata 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);
}
Run Code Online (Sandbox Code Playgroud)

要调用它,请使用以下内容:

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

console.log(canUserSeeIt); // true, if element is visible; false otherwise
Run Code Online (Sandbox Code Playgroud)


rpe*_*rce 6

这个好答案的基础上,您可以使用ES2015 +进一步简化它:

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

如果您不在乎顶部从窗口中伸出,而只是在乎底部已被查看,则可以简化为

function isSeen(el) {
  return el.getBoundingClientRect().bottom <= window.innerHeight
}
Run Code Online (Sandbox Code Playgroud)

甚至单线

const isSeen = el => el.getBoundingClientRect().bottom <= window.innerHeight
Run Code Online (Sandbox Code Playgroud)


fat*_*emi 6

Javascript 代码可以写成:

window.addEventListener('scroll', function() {
    var element = document.querySelector('#main-container');
    var position = element.getBoundingClientRect();

    // checking whether fully visible
    if(position.top >= 0 && position.bottom <= window.innerHeight) {
        console.log('Element is fully visible in screen');
    }

    // checking for partial visibility
    if(position.top < window.innerHeight && position.bottom >= 0) {
        console.log('Element is partially visible in screen');
    }
});
Run Code Online (Sandbox Code Playgroud)

在react js中写成:

    componentDidMount() {
        window.addEventListener('scroll', this.isScrolledIntoView);
    }

    componentWillUnmount() {
        window.removeEventListener('scroll', this.isScrolledIntoView);
    }
  
  isScrolledIntoView() {
        var element = document.querySelector('.element');
        var position = element.getBoundingClientRect();

        // checking whether fully visible
        if (position.top >= 0 && position.bottom <= window.innerHeight) {
            console.log('Element is fully visible in screen');
        }
        // checking for partial visibility
         if (position.top < window.innerHeight && position.bottom >= 0) {
            console.log('Element is partially visible in screen');
         }
    }
Run Code Online (Sandbox Code Playgroud)


Rom*_*las 5

我的应用程序中有这样的方法,但它不使用 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));
}
Run Code Online (Sandbox Code Playgroud)

编辑:此方法适用于 IE(至少版本 6)。请阅读注释以了解与 FF 的兼容性。


小智 5

我需要检查可滚动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);
    }
Run Code Online (Sandbox Code Playgroud)


pie*_*e6k 5

我更喜欢使用 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;  
    }
});
Run Code Online (Sandbox Code Playgroud)

所以你可以这样使用它

$(".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
Run Code Online (Sandbox Code Playgroud)

您可以轻松地在事件函数等中添加此类代码scroll,以在每次用户滚动视图时进行检查。