如何判断DOM元素在当前视口中是否可见?

问题描述 投票:831回答:23

是否有一种有效的方法来判断DOM元素(在HTML文档中)当前是否可见(出现在视口中)?

(问题是指Firefox)

javascript html firefox dom browser
23个回答
323
投票

更新:时间推进,我们的浏览器也是如此。如果您不需要支持IE <7,则不再推荐使用此技术,您应该使用@ Dan的解决方案(https://stackoverflow.com/a/7557433/5628)。

原始解决方案(现已过时):

这将检查元素在当前视口中是否完全可见:

function elementInViewport(el) {
  var top = el.offsetTop;
  var left = el.offsetLeft;
  var width = el.offsetWidth;
  var height = el.offsetHeight;

  while(el.offsetParent) {
    el = el.offsetParent;
    top += el.offsetTop;
    left += el.offsetLeft;
  }

  return (
    top >= window.pageYOffset &&
    left >= window.pageXOffset &&
    (top + height) <= (window.pageYOffset + window.innerHeight) &&
    (left + width) <= (window.pageXOffset + window.innerWidth)
  );
}

您可以简单地修改它以确定元素的任何部分是否在视口中可见:

function elementInViewport2(el) {
  var top = el.offsetTop;
  var left = el.offsetLeft;
  var width = el.offsetWidth;
  var height = el.offsetHeight;

  while(el.offsetParent) {
    el = el.offsetParent;
    top += el.offsetTop;
    left += el.offsetLeft;
  }

  return (
    top < (window.pageYOffset + window.innerHeight) &&
    left < (window.pageXOffset + window.innerWidth) &&
    (top + height) > window.pageYOffset &&
    (left + width) > window.pageXOffset
  );
}

8
投票

我发现这里接受的答案对于大多数用例而言过于复杂。此代码可以很好地完成工作(使用JQuery),并区分完全可见和部分可见的元素。

var element         = $("#element");
var topOfElement    = element.offset().top;
var bottomOfElement = element.offset().top + element.outerHeight(true);
var $window         = $(window);

$window.bind('scroll', function() {

    var scrollTopPosition   = $window.scrollTop()+$window.height();
    var windowScrollTop     = $window.scrollTop()

    if( windowScrollTop > topOfElement && windowScrollTop < bottomOfElement) {
       // Element is partially visible (above viewable area)
       console.log("Element is partially visible (above viewable area)");

    }else if( windowScrollTop > bottomOfElement && windowScrollTop > topOfElement ) {
        // Element is hidden (above viewable area)
       console.log("Element is hidden (above viewable area)");

    }else if( scrollTopPosition < topOfElement && scrollTopPosition < bottomOfElement ) {
        // Element is hidden (below viewable area)
        console.log("Element is hidden (below viewable area)");

    }else if( scrollTopPosition < bottomOfElement && scrollTopPosition > topOfElement ) {
        // Element is partially visible (below viewable area)
        console.log("Element is partially visible (below viewable area)");

    }else{
        // Element is completely visible
        console.log("Element is completely visible");
    }
});

5
投票

我在这里遇到的所有答案只检查元素是否位于当前视口内。但这并不意味着它是可见的。 如果给定元素位于具有溢出内容的div内,并且滚动出视图,该怎么办?

要解决这个问题,您必须检查所有父项是否包含该元素。 我的解决方案正是如此:

它还允许您指定要显示的元素数量。

Element.prototype.isVisible = function(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 = this.getBoundingClientRect();
    var parentRects = [];
    var element = this;

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

这个解决方案忽略了这样一个事实,即由于其他事实,例如opacity: 0,元素可能不可见。

我在Chrome和Internet Explorer 11中测试了此解决方案。


4
投票

新的Intersection Observer API非常直接地解决了这个问题。

这个解决方案需要一个polyfill作为Safari,Opera和IE还不支持这个。 (填充物包含在溶液中)。

在此解决方案中,有一个视图中的框是目标(观察到的)。当它进入视图时,标题顶部的按钮被隐藏。一旦盒子离开视图就会显示出来。

const buttonToHide = document.querySelector('button');

const hideWhenBoxInView = new IntersectionObserver((entries) => {
  if (entries[0].intersectionRatio <= 0) { // If not in view
    buttonToHide.style.display = "inherit";
  } else {
    buttonToHide.style.display = "none";
  }
});

hideWhenBoxInView.observe(document.getElementById('box'));
header {
  position: fixed;
  top: 0;
  width: 100vw;
  height: 30px;
  background-color: lightgreen;
}

.wrapper {
  position: relative;
  margin-top: 600px;
}

#box {
  position: relative;
  left: 175px;
  width: 150px;
  height: 135px;
  background-color: lightblue;
  border: 2px solid;
}
<script src="https://polyfill.io/v2/polyfill.min.js?features=IntersectionObserver"></script>
<header>
  <button>NAVIGATION BUTTON TO HIDE</button>
</header>
  <div class="wrapper">
    <div id="box">
    </div>
  </div>

3
投票

我认为这是一种更实用的方法。 Dan的答案在递归上下文中不起作用。

当你的元素在其他可滚动div中时,通过在HTML标记上递归地测试任何级别,并在第一个false中停止,此函数解决了这个问题。

/**
 * fullVisible=true only returns true if the all object rect is visible
 */
function isReallyVisible(el, fullVisible) {
    if ( el.tagName == "HTML" )
            return true;
    var parentRect=el.parentNode.getBoundingClientRect();
    var rect = arguments[2] || el.getBoundingClientRect();
    return (
            ( fullVisible ? rect.top    >= parentRect.top    : rect.bottom > parentRect.top ) &&
            ( fullVisible ? rect.left   >= parentRect.left   : rect.right  > parentRect.left ) &&
            ( fullVisible ? rect.bottom <= parentRect.bottom : rect.top    < parentRect.bottom ) &&
            ( fullVisible ? rect.right  <= parentRect.right  : rect.left   < parentRect.right ) &&
            isReallyVisible(el.parentNode, fullVisible, rect)
    );
};

2
投票

基于@ dan的上述解决方案(https://stackoverflow.com/a/7557433/5628),我开始清理实现,以便在同一页面上多次使用它更容易:

$(function() {

  $(window).on('load resize scroll', function() {
    addClassToElementInViewport($('.bug-icon'), 'animate-bug-icon');
    addClassToElementInViewport($('.another-thing'), 'animate-thing');
    // 👏 repeat as needed ...
  });

  function addClassToElementInViewport(element, newClass) {
    if (inViewport(element)) {
      element.addClass(newClass);
    }
  }

  function inViewport(element) {
    if (typeof jQuery === "function" && element instanceof jQuery) {
      element = element[0];
    }
    var elementBounds = element.getBoundingClientRect();
    return (
      elementBounds.top >= 0 &&
      elementBounds.left >= 0 &&
      elementBounds.bottom <= $(window).height() &&
      elementBounds.right <= $(window).width()
    );
  }

});

我使用它的方式是当元素滚动到视图中时,我添加了一个触发css关键帧动画的类。这是非常简单的,当你有10个以上的东西在页面上有条件地制作动画时效果特别好。

希望能帮助到你!


1
投票

这是我的解决方案,如果元素隐藏在可滚动容器中,它将起作用。

qazxsw诗歌调整窗口大小)

Here's a demo

我只需要检查它是否在Y轴上可见(对于滚动ajax加载更多记录功能)。


1
投票

这个简单而小巧的解决方案对我有用。

示例您想要查看元素在具有溢出滚动的父元素中是否可见。

var visibleY = function(el){
    var top = el.getBoundingClientRect().top, rect, el = el.parentNode;
    do {
        rect = el.getBoundingClientRect();
        if (top <= rect.bottom === false)
            return false;
        el = el.parentNode;
    } while (el != document.body);
    // Check its within the document viewport
    return top <= document.documentElement.clientHeight;
};

0
投票

更好的解决方案:

$(window).on('scroll', function () {  

     var container = $('#sidebar');
     var containerHeight = container.height();
     var scrollPosition = $('#row1').offset().top - container.offset().top;

     if (containerHeight < scrollPosition) {
         console.log('not visible');
     } else {
         console.log('visible');
     }
})

0
投票

检查元素是否至少部分在视图中(垂直尺寸):

function getViewportSize(w) {
    var w = w || window;
    if(w.innerWidth != null) return {w:w.innerWidth, h:w.innerHeight};
    var d = w.document;
    if (document.compatMode == "CSS1Compat") {
        return {
            w: d.documentElement.clientWidth,
            h: d.documentElement.clientHeight
        };
    }
    return { w: d.body.clientWidth, h: d.body.clientWidth };
}
function isViewportVisible(e) {
    var box = e.getBoundingClientRect();
    var height = box.height || (box.bottom - box.top);
    var width = box.width || (box.right - box.left);
    var viewport = getViewportSize();
    if(!height || !width) return false;
    if(box.top > viewport.h || box.bottom < 0) return false;
    if(box.right < 0 || box.left > viewport.w) return false;
    return true;    
}

0
投票

我有同样的问题,并通过使用getBoundingClientRect()来计算出来。此代码完全是“通用的”,只需编写一次即可使用(您不必为要知道的每个元素在视口中写出来)。此代码仅检查视口中是否垂直,而不是水平。在这种情况下,变量(数组)'elements'保存您在视口中垂直检查的所有元素,因此在任何地方抓取您想要的任何元素并将它们存储在那里。 'for循环'循环遍历每个元素并检查它是否在视口中是垂直的。每次用户滚动时都会执行此代码!如果getBoudingClientRect()。top小于视口的3/4(该元素在视口中是四分之一),则它将注册为“在视口中”。由于代码是通用的,因此您需要知道视口中的“哪个”元素。要找到它,您可以通过自定义属性,节点名称,ID,类名等来确定它。这是我的代码(告诉我,如果它不起作用,它已经在IE 11,FireFox 40.0.3,Chrome版本45.0.2454.85 m,Opera 31.0.1889.174和Edge与Windows 10,[还没有Safari]中进行了测试)...

function inView(element) {
                var box = element.getBoundingClientRect();
                return inViewBox(box);
}

function inViewBox(box) {
                return ((box.bottom < 0) || (box.top > getWindowSize().h)) ? false : true;
}


function getWindowSize() { 
        return { w: document.body.offsetWidth || document.documentElement.offsetWidth || window.innerWidth, h: document.body.offsetHeight || document.documentElement.offsetHeight || window.innerHeight} 
}

希望这有助于某人:-)


1306
投票

现在most browsers支持getBoundingClientRect方法,这已成为最佳实践。使用旧的答案是very slownot accuratehas several bugs

选择正确的解决方案是almost never precise。你可以read more关于它的错误。


此解决方案在IE7 +,iOS5 + Safari,Android2 +,Blackberry,Opera Mobile和IE Mobile 10上进行了测试。


function isElementInViewport (el) {

    //special bonus for those using jQuery
    if (typeof jQuery === "function" && el instanceof jQuery) {
        el = el[0];
    }

    var rect = el.getBoundingClientRect();

    return (
        rect.top >= 0 &&
        rect.left >= 0 &&
        rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */
        rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */
    );
}

如何使用:

您可以确定上面给出的函数在调用时返回正确的答案,但是跟踪元素作为事件的可见性呢?

将以下代码放在<body>标记的底部:

function onVisibilityChange(el, callback) {
    var old_visible;
    return function () {
        var visible = isElementInViewport(el);
        if (visible != old_visible) {
            old_visible = visible;
            if (typeof callback == 'function') {
                callback();
            }
        }
    }
}

var handler = onVisibilityChange(el, function() {
    /* your code go here */
});


//jQuery
$(window).on('DOMContentLoaded load resize scroll', handler); 

/* //non-jQuery
if (window.addEventListener) {
    addEventListener('DOMContentLoaded', handler, false); 
    addEventListener('load', handler, false); 
    addEventListener('scroll', handler, false); 
    addEventListener('resize', handler, false); 
} else if (window.attachEvent)  {
    attachEvent('onDOMContentLoaded', handler); // IE9+ :(
    attachEvent('onload', handler);
    attachEvent('onscroll', handler);
    attachEvent('onresize', handler);
}
*/

如果您进行任何DOM修改,它们可以改变元素的可见性。

准则和常见陷阱:

也许你需要跟踪页面缩放/移动设备捏? jQuery应该处理zoom/pinch跨浏览器,否则firstsecond链接应该可以帮助你。

如果修改DOM,则会影响元素的可见性。您应该控制它并手动调用handler()。不幸的是,我们没有跨浏览器onrepaint事件。另一方面,它允许我们进行优化并仅对可以改变元素可见性的DOM修改执行重新检查。

从来没有在jQuery $(document).ready()中使用它,因为there is no warranty CSS has been applied在这一刻。您的代码可以在硬盘驱动器上与您的CSS本地工作,但一旦放在远程服务器上它将失败。

DOMContentLoaded被解雇后,styles are applied,但the images are not loaded yet。所以,我们应该添加window.onload事件监听器。

我们还无法捕捉缩放/捏合事件。

最后的手段可能是以下代码:

/* TODO: this looks like a very bad code */
setInterval(handler, 600); 

如果您关心网页的标签是否有效且可见,您可以使用真棒功能pageVisibiliy HTML5 API。

TODO:此方法不处理两种情况:


0
投票

这是一个函数,它告诉一个元素在父元素的当前视口中是否可见:

//scrolling handlers...
window.onscroll = function(){
  var elements = document.getElementById('whatever').getElementsByClassName('whatever');
  for(var i = 0; i != elements.length; i++)
  {
   if(elements[i].getBoundingClientRect().top <= window.innerHeight*0.75 && elements[i].getBoundingClientRect().top > 0)
   {
      console.log(elements[i].nodeName + ' ' + elements[i].className + ' ' + elements[i].id + ' is in the viewport; proceed with whatever code you want to do here.');
   }
};

0
投票

尽可能简单到IMO:

function inParentViewport(el, pa) {
    if (typeof jQuery === "function"){
        if (el instanceof jQuery)
            el = el[0];
        if (pa instanceof jQuery)
            pa = pa[0];
    }

    var e = el.getBoundingClientRect();
    var p = pa.getBoundingClientRect();

    return (
        e.bottom >= p.top &&
        e.right >= p.left &&
        e.top <= p.bottom &&
        e.left <= p.right
    );
}

0
投票

最简单的解决方案,因为function isVisible(elem) { var coords = elem.getBoundingClientRect(); return Math.abs(coords.top) <= coords.height; } compatibility已经变得完美:

Element.getBoundingClientRect()

-1
投票

我使用这个功能(它只检查y是否是屏幕,因为大部分时间不需要x)

function inView(el) {
    let box = el.getBoundingClientRect();
    return box.top < window.innerHeight && box.bottom >= 0;
}

-2
投票

对于类似的挑战,我非常喜欢function elementInViewport(el) { var elinfo = { "top":el.offsetTop, "height":el.offsetHeight, }; if (elinfo.top + elinfo.height < window.pageYOffset || elinfo.top > window.pageYOffset + window.innerHeight) { return false; } else { return true; } } ,它为this gist暴露了一种polyfill。

所有必要的功夫都需要回答这个问题:

scrollIntoViewIfNeeded()

var parent = this.parentNode, parentComputedStyle = window.getComputedStyle(parent, null), parentBorderTopWidth = parseInt(parentComputedStyle.getPropertyValue('border-top-width')), parentBorderLeftWidth = parseInt(parentComputedStyle.getPropertyValue('border-left-width')), overTop = this.offsetTop - parent.offsetTop < parent.scrollTop, overBottom = (this.offsetTop - parent.offsetTop + this.clientHeight - parentBorderTopWidth) > (parent.scrollTop + parent.clientHeight), overLeft = this.offsetLeft - parent.offsetLeft < parent.scrollLeft, overRight = (this.offsetLeft - parent.offsetLeft + this.clientWidth - parentBorderLeftWidth) > (parent.scrollLeft + parent.clientWidth), alignWithTop = overTop && !overBottom; 指的是你想要知道的元素,如果它是thisoverTop - 只是应该得到漂移......


151
投票

更新

在现代浏览器中,您可能需要查看Intersection Observer API,它具有以下优点:

  • 比收听滚动事件更好的性能
  • 适用于跨域iframe
  • 可以判断一个元素是否阻碍/交叉另一个元素

Intersection Observer正在成为一个成熟的标准,并已在Chrome 51 +,Edge 15+和Firefox 55+中得到支持,并且正在开发Safari。还有一个polyfill可用。


以前的答案

answer provided by Dan存在一些问题,这些问题可能使其成为某些情况下不适合的方法。其中一些问题在他的答案附近指出,他的代码将给出以下元素的误报:

  • 被测试者面前的另一个元素隐藏
  • 在父元素或祖先元素的可见区域之外
  • 使用CSS clip属性隐藏的元素或其子元素

这些限制在simple test的以下结果中得到证明:

解决方案:isElementVisible()

以下是这些问题的解决方案,下面是测试结果,并解释了代码的某些部分。

function isElementVisible(el) {
    var rect     = el.getBoundingClientRect(),
        vWidth   = window.innerWidth || doc.documentElement.clientWidth,
        vHeight  = window.innerHeight || doc.documentElement.clientHeight,
        efp      = function (x, y) { return document.elementFromPoint(x, y) };     

    // Return false if it's not in the viewport
    if (rect.right < 0 || rect.bottom < 0 
            || rect.left > vWidth || rect.top > vHeight)
        return false;

    // Return true if any of its four corners are visible
    return (
          el.contains(efp(rect.left,  rect.top))
      ||  el.contains(efp(rect.right, rect.top))
      ||  el.contains(efp(rect.right, rect.bottom))
      ||  el.contains(efp(rect.left,  rect.bottom))
    );
}

通过测试:http://jsfiddle.net/AndyE/cAY8c/

结果如下:

补充说明

然而,这种方法并非没有自身的局限性。例如,即使前面的元素实际上没有隐藏它的任何部分,使用比同一位置的另一个元素更低的z-index测试的元素也将被识别为隐藏。尽管如此,这种方法在某些情况下仍然使用Dan的解决方案。

element.getBoundingClientRect()document.elementFromPoint()都是CSSOM工作草案规范的一部分,并且至少在IE 6及更高版本和大多数桌面浏览器中都受到支持很长时间(尽管不是很完美)。有关更多信息,请参阅Quirksmode on these functions

contains()用于查看document.elementFromPoint()返回的元素是否是我们正在测试可见性的元素的子节点。如果返回的元素是相同的元素,它也返回true。这只会使检查更加健壮。所有主流浏览器都支持它,Firefox 9.0是最后一个添加它的人。对于较早的Firefox支持,请查看此答案的历史记录。

如果你想在元素周围测试更多的点以获得可见性 - 也就是说,为了确保元素不被覆盖超过50%,那么调整答案的最后部分并不需要太多。但是,请注意,如果检查每个像素以确保它是100%可见,则可能会非常慢。


57
投票

我试过Dan's answer然而用于确定边界的代数意味着该元素必须既是视口大小又完全在视口内部以获得true,容易导致假阴性。如果要确定元素是否在视口中,ryanve's answer是关闭的,但正在测试的元素应该与视口重叠,所以试试这个:

function isElementInViewport(el) {
    var rect = el.getBoundingClientRect();

    return rect.bottom > 0 &&
        rect.right > 0 &&
        rect.left < (window.innerWidth || document.documentElement.clientWidth) /* or $(window).width() */ &&
        rect.top < (window.innerHeight || document.documentElement.clientHeight) /* or $(window).height() */;
}

30
投票

作为公共服务: Dan的答案是正确的计算(元素可以是>窗口,特别是在手机屏幕上),正确的jQuery测试,以及添加isElementPartiallyInViewport:

顺便说一句,window.innerWidth和document.documentElement.clientWidth之间的difference是clientWidth / clientHeight不包含滚动条,而window.innerWidth / Height则包含滚动条。

function isElementPartiallyInViewport(el)
{
    //special bonus for those using jQuery
    if (typeof jQuery !== 'undefined' && el instanceof jQuery) el = el[0];

    var rect = el.getBoundingClientRect();
    // DOMRect { x: 8, y: 8, width: 100, height: 100, top: 8, right: 108, bottom: 108, left: 8 }
    var windowHeight = (window.innerHeight || document.documentElement.clientHeight);
    var windowWidth = (window.innerWidth || document.documentElement.clientWidth);

    // http://stackoverflow.com/questions/325933/determine-whether-two-date-ranges-overlap
    var vertInView = (rect.top <= windowHeight) && ((rect.top + rect.height) >= 0);
    var horInView = (rect.left <= windowWidth) && ((rect.left + rect.width) >= 0);

    return (vertInView && horInView);
}


// http://stackoverflow.com/questions/123999/how-to-tell-if-a-dom-element-is-visible-in-the-current-viewport
function isElementInViewport (el) 
{
    //special bonus for those using jQuery
    if (typeof jQuery !== 'undefined' && el instanceof jQuery) el = el[0];

    var rect = el.getBoundingClientRect();
    var windowHeight = (window.innerHeight || document.documentElement.clientHeight);
    var windowWidth = (window.innerWidth || document.documentElement.clientWidth);

    return (
           (rect.left >= 0)
        && (rect.top >= 0)
        && ((rect.left + rect.width) <= windowWidth)
        && ((rect.top + rect.height) <= windowHeight)
    );

}


function fnIsVis(ele)
{
    var inVpFull = isElementInViewport(ele);
    var inVpPartial = isElementPartiallyInViewport(ele);
    console.clear();
    console.log("Fully in viewport: " + inVpFull);
    console.log("Partially in viewport: " + inVpPartial);
}

测试用例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="author" content="">
    <title>Test</title>
    <!--
    <script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>    
    <script src="scrollMonitor.js"></script>
    -->

    <script type="text/javascript">

        function isElementPartiallyInViewport(el)
        {
            //special bonus for those using jQuery
            if (typeof jQuery !== 'undefined' && el instanceof jQuery) el = el[0];

            var rect = el.getBoundingClientRect();
            // DOMRect { x: 8, y: 8, width: 100, height: 100, top: 8, right: 108, bottom: 108, left: 8 }
            var windowHeight = (window.innerHeight || document.documentElement.clientHeight);
            var windowWidth = (window.innerWidth || document.documentElement.clientWidth);

            // http://stackoverflow.com/questions/325933/determine-whether-two-date-ranges-overlap
            var vertInView = (rect.top <= windowHeight) && ((rect.top + rect.height) >= 0);
            var horInView = (rect.left <= windowWidth) && ((rect.left + rect.width) >= 0);

            return (vertInView && horInView);
        }


        // http://stackoverflow.com/questions/123999/how-to-tell-if-a-dom-element-is-visible-in-the-current-viewport
        function isElementInViewport (el) 
        {
            //special bonus for those using jQuery
            if (typeof jQuery !== 'undefined' && el instanceof jQuery) el = el[0];


            var rect = el.getBoundingClientRect();
            var windowHeight = (window.innerHeight || document.documentElement.clientHeight);
            var windowWidth = (window.innerWidth || document.documentElement.clientWidth);

            return (
                   (rect.left >= 0)
                && (rect.top >= 0)
                && ((rect.left + rect.width) <= windowWidth)
                && ((rect.top + rect.height) <= windowHeight)
            );

        }


        function fnIsVis(ele)
        {
            var inVpFull = isElementInViewport(ele);
            var inVpPartial = isElementPartiallyInViewport(ele);
            console.clear();
            console.log("Fully in viewport: " + inVpFull);
            console.log("Partially in viewport: " + inVpPartial);
        }


        // var scrollLeft = (window.pageXOffset !== undefined) ? window.pageXOffset : (document.documentElement || document.body.parentNode || document.body).scrollLeft,
        // var scrollTop = (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;

    </script>

</head>
<body>

    <div style="display: block; width: 2000px; height: 10000px; background-color: green;">

        <br /><br /><br /><br /><br /><br />
        <br /><br /><br /><br /><br /><br />
        <br /><br /><br /><br /><br /><br />

        <input type="button" onclick="fnIsVis(document.getElementById('myele'));" value="det" />

        <br /><br /><br /><br /><br /><br />
        <br /><br /><br /><br /><br /><br />
        <br /><br /><br /><br /><br /><br />

        <div style="background-color: crimson; display: inline-block; width: 800px; height: 500px;" ></div>
        <div id="myele" onclick="fnIsVis(this);" style="display: inline-block; width: 100px; height: 100px; background-color: hotpink;">
        t
        </div>

        <br /><br /><br /><br /><br /><br />
        <br /><br /><br /><br /><br /><br />
        <br /><br /><br /><br /><br /><br />

        <input type="button" onclick="fnIsVis(document.getElementById('myele'));" value="det" />

    </div>

    <!--
    <script type="text/javascript">

        var element = document.getElementById("myele");
        var watcher = scrollMonitor.create( element );

        watcher.lock();

        watcher.stateChange(function() {
            console.log("state changed");
            // $(element).toggleClass('fixed', this.isAboveViewport)
        });

    </script>
    -->
</body>
</html>

24
投票

有一个名为inview的jQuery插件可以完成这项工作


24
投票

查看使用vergegetBoundingClientRect的来源。就像是:

function inViewport (el) {

    var r, html;
    if ( !el || 1 !== el.nodeType ) { return false; }
    html = document.documentElement;
    r = el.getBoundingClientRect();

    return ( !!r 
      && r.bottom >= 0 
      && r.right >= 0 
      && r.top <= html.clientHeight 
      && r.left <= html.clientWidth 
    );

}

如果元素的任何部分位于视口中,则返回true


23
投票

我更短更快的版本。

function isElementOutViewport(el){
    var rect = el.getBoundingClientRect();
    return rect.bottom < 0 || rect.right < 0 || rect.left > window.innerWidth || rect.top > window.innerHeight;
}

根据需要添加jsFiddle https://jsfiddle.net/on1g619L/1/


19
投票

我发现令人不安的是,没有以jQuery为中心的功能版本。当我遇到Dan's solution时,我发现有机会为喜欢以jQuery OO风格编程的人提供一些东西。请务必向上滚动并在Dan的代码上保留一个upvote。它漂亮而活泼,对我来说就像是一种魅力。

bada bing bada boom

$.fn.inView = function(){
    if(!this.length) return false;
    var rect = this.get(0).getBoundingClientRect();

    return (
        rect.top >= 0 &&
        rect.left >= 0 &&
        rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
        rect.right <= (window.innerWidth || document.documentElement.clientWidth)
    );

};

//additional examples for other use cases
//true false whether an array of elements are all in view
$.fn.allInView = function(){
    var all = [];
    this.forEach(function(){
        all.push( $(this).inView() );
    });
    return all.indexOf(false) === -1;
};

//only the class elements in view
$('.some-class').filter(function(){
    return $(this).inView();
});

//only the class elements not in view
$('.some-class').filter(function(){
    return !$(this).inView();
});

用法

$(window).on('scroll',function(){ 

    if( $('footer').inView() ) {
        // do cool stuff
    }

});
© www.soinside.com 2019 - 2024. All rights reserved.