javascript 检测可滚动 div 中的元素何时不在视图中

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16308037/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 04:08:59  来源:igfitidea点击:

Detect when elements within a scrollable div are out of view

javascriptjqueryhtmltrackingviewport

提问by Ronny

I need to find a good solution to the following problem. I see a lot of people asking about tracking if an element is in or outside of view Port for the page or browser window. I need to be able to replicate this action, but inside a DIV that scrolls, with overflow:scroll for example. Does anyone know of a good example, for this specific action?

我需要找到一个很好的解决方案来解决以下问题。我看到很多人询问跟踪元素是否在页面或浏览器窗口的视图端口内或外。我需要能够复制此操作,但是在滚动的 DIV 中,例如使用 overflow:scroll。有没有人知道这个特定行动的好例子?

Thanks in advance.

提前致谢。

回答by Akram Berkawy

i had the same problem before, i have ended up with the following function.the first parameter is for the element to check, the second is to check if the element is partially in-view.it is for vertical check only, you can extend it to check for horizontal scroll.

我之前遇到过同样的问题,我最终得到了以下函数。第一个参数是要检查的元素,第二个是检查元素是否部分在视图中。它仅用于垂直检查,您可以扩展它检查水平滚动。

function checkInView(elem,partial)
{
    var container = $(".scrollable");
    var contHeight = container.height();
    var contTop = container.scrollTop();
    var contBottom = contTop + contHeight ;

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

    var isTotal = (elemTop >= 0 && elemBottom <=contHeight);
    var isPart = ((elemTop < 0 && elemBottom > 0 ) || (elemTop > 0 && elemTop <= container.height())) && partial ;

    return  isTotal  || isPart ;
}

check it on jsFiddle.

jsFiddle上检查它。

回答by Adam Reis

Here's a pure javascript version of the accepted answer without relying on jQuery and with some fixes to the partial in view detection and support for out of view on top.

这是已接受答案的纯 javascript 版本,不依赖于 jQuery,并且对局部视图检测和顶部视图外的支持进行了一些修复。

function checkInView(container, element, partial) {

    //Get container properties
    let cTop = container.scrollTop;
    let cBottom = cTop + container.clientHeight;

    //Get element properties
    let eTop = element.offsetTop;
    let eBottom = eTop + element.clientHeight;

    //Check if in view    
    let isTotal = (eTop >= cTop && eBottom <= cBottom);
    let isPartial = partial && (
      (eTop < cTop && eBottom > cTop) ||
      (eBottom > cBottom && eTop < cBottom)
    );

    //Return outcome
    return  (isTotal  || isPartial);
}

And as a bonus, this function ensures the element is in view if it's not (partial or full):

作为奖励,如果元素不是(部分或完整),此函数可确保元素在视图中:

function ensureInView(container, element) {

    //Determine container top and bottom
    let cTop = container.scrollTop;
    let cBottom = cTop + container.clientHeight;

    //Determine element top and bottom
    let eTop = element.offsetTop;
    let eBottom = eTop + element.clientHeight;

    //Check if out of view
    if (eTop < cTop) {
      container.scrollTop -= (cTop - eTop);
    }
    else if (eBottom > cBottom) {
      container.scrollTop += (eBottom - cBottom);
    }
}

回答by Jonny Ngan

Based of the best answer. Instead of just telling you if an element is partially visible or not. I added a little extra so you can pass in a percentage (0-100) that tells you if the element is more than x% visible.

基于最佳答案。而不是仅仅告诉你一个元素是否部分可见。我添加了一些额外的内容,以便您可以传入一个百分比 (0-100),告诉您元素是否超过 x% 可见。

function (container, element, partial) {
    var cTop = container.scrollTop;
    var cBottom = cTop + container.clientHeight;
    var eTop = element.offsetTop;
    var eBottom = eTop + element.clientHeight;
    var isTotal = (eTop >= cTop && eBottom <= cBottom);
    var isPartial;

    if (partial === true) {
        isPartial = (eTop < cTop && eBottom > cTop) || (eBottom > cBottom && eTop < cBottom);
    } else if(typeof partial === "number"){
        if (eTop < cTop && eBottom > cTop) {
            isPartial = ((eBottom - cTop) * 100) / element.clientHeight > partial;
        } else if (eBottom > cBottom && eTop < cBottom){ 
            isPartial = ((cBottom - eTop) * 100) / element.clientHeight > partial;
        }
    }
    return (isTotal || isPartial);
}

回答by palerdot

I was able to make this work by making a small change to the pure javascript version posted

我能够通过对发布的纯 javascript 版本进行小的更改来完成这项工作

function checkInView(container, element, partial) {

    //Get container properties
    let cTop = container.scrollTop;
    let cBottom = cTop + container.clientHeight;

    //Get element properties
    let eTop = element.offsetTop - container.offsetTop; // change here
    let eBottom = eTop + element.clientHeight;

    //Check if in view    
    let isTotal = (eTop >= cTop && eBottom <= cBottom);
    let isPartial = partial && (
      (eTop < cTop && eBottom > cTop) ||
      (eBottom > cBottom && eTop < cBottom)
    );

    //Return outcome
    return  (isTotal  || isPartial);
  }

回答by Abdul Alim

Here is a pure javascript solution.

这是一个纯javascript解决方案。

function elementIsVisible(element, container, partial) {
    var contHeight = container.offsetHeight,
    elemTop = offset(element).top - offset(container).top,
    elemBottom = elemTop + element.offsetHeight;
    return (elemTop >= 0 && elemBottom <= contHeight) || 
    (partial && ((elemTop < 0 && elemBottom > 0 ) || (elemTop > 0 && elemTop <= contHeight)))
}

// checks window
function isWindow( obj ) {
    return obj != null && obj === obj.window;
}

// returns corresponding window
function getWindow( elem ) {
    return isWindow( elem ) ? elem : elem.nodeType === 9 && elem.defaultView;
}

// taken from jquery
// @returns {{top: number, left: number}} 
function offset( elem ) {

    var docElem, win,
        box = { top: 0, left: 0 },
        doc = elem && elem.ownerDocument;

    docElem = doc.documentElement;

    if ( typeof elem.getBoundingClientRect !== typeof undefined ) {
        box = elem.getBoundingClientRect();
    }
    win = getWindow( doc );
    return {
        top: box.top + win.pageYOffset - docElem.clientTop,
        left: box.left + win.pageXOffset - docElem.clientLeft
    };
};

回答by David

I made a jquery plugin with the last answer:

我用最后一个答案制作了一个 jquery 插件:

(function($) {
    $.fn.reallyVisible = function(opt) {

        var options = $.extend({
            cssChanges:[
                { name : 'visibility', states : ['hidden','visible'] }
            ],
            childrenClass:'mentioners2',
            partialview : true
        }, opt);

        var container = $(this);
        var contHeight;
        var contTop;
        var contBottom;
        var _this = this;
        var _children;

        this.checkInView = function(elem,partial){

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

            var isTotal = (elemTop >= 0 && elemBottom <=contHeight);
            var isPart = ((elemTop < 0 && elemBottom > 0 ) || (elemTop > 0 && elemTop <= container.height())) && partial ;

            return  isTotal  || isPart ;
        }

        this.bind('restoreProperties',function(){
            $.each(_children,function(i,elem){
                $.each(options.cssChanges,function(i,_property){
                    $(elem).css(_property.name,_property.states[1]);        
                });
            });
            _children = null;
        });

        return this.each(function(){
            contHeight = container.height();
            contTop = container.scrollTop();
            contBottom = contTop + contHeight ;

            _children = container.children("."+options.childrenClass);

            $.each(_children,function(i,elem){
                var res = _this.checkInView(elem,options.partialview);
                if(  !res ){
                    $.each(options.cssChanges,function(i,_property){
                        $(elem).css(_property.name,_property.states[0]);        
                    });
                }
            });

        }); 
    }

})(jQuery);

回答by Sarath Ak

You can try this

你可以试试这个

function isScrolledIntoView(elem) {
    var docViewTop = $(window).scrollTop();
    var docViewBottom = docViewTop + window.innerHeight;
    var el = $(elem);
    var elemTop = el.offset().top;
    var elemBottom = elemTop + el.height();
    var elemDisplayNotNone = el.css("display") !== "none";

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

eg:

例如:

isScrolledIntoView('#button')