滚动后检查元素是否可见
我通过AJAX加载元素。 其中一些只有在向下滚动页面时才可见。
有什么办法可以知道一个元素是否在页面的可见部分?
这应该做的伎俩:
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这将允许您调用接受您要查找的元素的实用程序函数,以及是否希望元素完全处于视图或部分视图中。
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'); }
Vanilla的这个答案 :
function isScrolledIntoView(el) { var elemTop = el.getBoundingClientRect().top; var elemBottom = el.getBoundingClientRect().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; }
到目前为止我发现的最好的方法是jQuery插件 。 奇迹般有效。
模仿一个自定义的“出现”事件,当元素滚动到视图中或以其他方式变得对用户可见时触发。
$('#foo').appear(function() { $(this).text('Hello world'); });
这个插件可以用来防止对隐藏的内容或可视区域之外的不必要的请求。
这是我纯粹的JavaScript解决scheme,如果它隐藏在一个可滚动的容器内,也可以工作。
在这里演示 (尝试调整窗口的大小)
var visibleY = function(el){ var rect = el.getBoundingClientRect(), top = rect.top, height = rect.height, el = el.parentNode; 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); // Check its within the document viewport return top <= document.documentElement.clientHeight; };
编辑2016-03-26:我已经更新了解决scheme,考虑滚动过去的元素,所以它隐藏在可卷动容器的顶部之上。
jQuery的Waypoint插件在这里非常好。
$('.entry').waypoint(function() { alert('You have scrolled to an entry.'); });
在插件的网站上有一些例子。
WebResourcesDepot写了一个脚本来加载滚动 ,前一段时间使用jQuery 。 您可以在这里查看他们的实时演示 。 他们function的牛肉是这样的:
$(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(); }); };
Tweeked斯科特Dowding的冷却function,我的要求,这是用来发现元素是否刚刚滚动到屏幕上,即它的顶部边缘。
function isScrolledIntoView(elem) { var docViewTop = $(window).scrollTop(); var docViewBottom = docViewTop + $(window).height(); var elemTop = $(elem).offset().top; return ((elemTop <= docViewBottom) && (elemTop >= docViewTop)); }
怎么样
function isInView(elem){ return $(elem).offset().top - $(window).scrollTop() < $(elem).height() ; }
之后,你可以触发任何你想要的元素一旦在这样的视图
$(window).scroll(function(){ if (isInView($('.classOfDivToCheck'))) //fire whatever you what dothis(); })
这对我来说很好
isScrolledIntoView是一个非常需要的function,所以我尝试了它,它适用于不比视口更高的元素,但是如果元素比视口更大,则它不起作用。 解决这个问题很容易改变条件
return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
对此:
return (docViewBottom >= elemTop && docViewTop <= elemBottom);
在此处查看演示: http : //jsfiddle.net/RRSmQ/
有一个名为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 );
我在这里发现了这个( http://remysharp.com/2009/01/26/element-in-view-event-plugin/ )由一个叫詹姆斯
这里有一个相当不错的例子(向下滚动到底部):
http://www.bbc.co.uk/sport/0/olympics/2012/
我不能100%确定该示例使用相同的代码,但…
编辑…我还写了一个名为“exitview”的插件插件的扩展,当元素离开页面时触发一个事件。 如果有可能的话,任何对代码感兴趣的人都可以提出。
这考虑了元素所具有的任何填充,边框或边距以及大于视口本身的元素。
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
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)); }
这里的大多数答案都没有考虑到一个元素也可以被隐藏,因为它是从div的视图中滚动出来的,而不是整个页面。
为了掩盖这种可能性,你基本上必须检查元素是否位于每个父母的边界内。
这个解决scheme确实如此:
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
。
这应该适用于所有主stream浏览器,因为它只使用getBoundingClientRect
。 我亲自在Chrome和Internet Explorer 11中进行了testing。
简单的香草来检查元素( el
)是否在可滚动div( holder
)中可见
function isScrolledIntoView(el, holder) { var elemTop = el.getBoundingClientRect().top; var elemBottom = el.getBoundingClientRect().bottom; var elemHeight = el.getBoundingClientRect().height; var holderTop = holder.getBoundingClientRect().top; var holderBottom = holder.getBoundingClientRect().bottom; var isVisible; if (elemTop <= holderTop) { isVisible = !(holderTop - elemTop > elemHeight); } else { isVisible = !(elemBottom - holderBottom > elemHeight); } return isVisible; }
使用jQuery:
var el = $('tr:last').get(0); var holder = $('table').get(0); isVisible = isScrolledIntoView(el, holder);
基于这个伟大的答案 ,你可以使用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
我在我的应用程序中有这样的方法,但它不使用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)); }
编辑:这种方法适用于IE浏览器(至less版本6)。 阅读与FF兼容性的注释。
如果你想调整这个滚动另一个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)); }
我需要检查可滚动的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); }
如果元素的任何部分在页面上可见,则此方法将返回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; }
我改编了这个简短的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)); };
我更喜欢使用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
事件function等内轻松地添加这样的代码,以检查每次用户将滚动视图。
修改接受的答案,以便元素必须将其显示属性设置为“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); }
这是来自http://web-profile.com.ua/的另一个解决scheme
<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中看到它
这是一种使用Mootools在水平,垂直或两者中实现相同的function的方法。
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); }});
简单修改滚动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,则不起作用。
你可以使用jQuery插件“onScreen”来检查当你滚动时元素是否在当前的视口中。 当select器出现在屏幕上时,插件将select器的“onScreen”设置为true。 这是可以包含在项目中的插件的链接。 “ 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; }
我正在寻找一种方法,看看元素是否会很快进入视图,所以通过扩展上面的片段我设法做到这一点。 以为我会离开这里,以防万一它会帮助别人
elm =是要检查的元素在视图中
scrollElement =你可以传递窗口或者有滚动的父元素
offset =如果你希望它在屏幕前200px的时候触发,然后通过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)); }
我为这个任务编写了一个组件 ,专门用来处理大量的元素(对于慢速移动中的 1000个元素来说,调用时间小于10ms)。
它适用于你有权访问的每种types的滚动容器 – 窗口,HTML元素,embedded式iframe,衍生的子窗口 – 并且在检测到的时候非常灵活( 全部或部分可见性 , 边框或内容框 ,自定义容差区域 等 )。
一个巨大的,主要是自动生成的testing套件可以确保它像广告一样, 跨浏览器工作 。
给它一个镜头,如果你喜欢: jQuery.isInView 。 否则,你可能会在源代码中find灵感,例如这里 。
一个基于这个答案的例子,用来检查一个元素是否可见(即less于屏幕的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; }
这个问题有30多个答案,他们都没有使用我一直使用的非常简单,纯粹的JS解决scheme。 没有必要加载jQuery来解决这个问题,正如许多其他人所推动的那样。
为了判断元素是否在视口内,我们必须首先确定元素在体内的位置。 我们不需要像我曾经想过的那样recursion地做这件事。 相反,我们可以使用element.getBoundingClientRect()
。
pos = elem.getBoundingClientRect().top - document.body.getBoundingClientRect().top;
该值是对象顶部与主体顶部之间的Y差异。
然后我们必须告诉元素是否在视图内。 大多数实现都会询问整个元素是否在视口内,所以这就是我们要讲的内容。
首先,窗口的顶部位置是: window.scrollY
。
我们可以通过将窗口的高度添加到顶部位置来获取窗口的底部位置:
var window_bottom_position = window.scrollY + window.innerHeight;
让我们创build一个简单的函数来获取元素的顶部位置:
function getElementWindowTop(elem){ return elem && typeof elem.getBoundingClientRect === 'function' ? elem.getBoundingClientRect().top - document.body.getBoundingClientRect().top : 0; }
该函数将返回元素在窗口内的顶部位置,或者如果使用.getBoundingClientRect()
方法传递元素而不是元素,它将返回0
。 这个方法已经存在很长时间了,所以你不必担心你的浏览器不支持它。
现在,我们元素的最高位置是:
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中使用转换效果处理。
我真的很惊讶,我没有find这个解决scheme,但我相信这是最干净和最有效的解决scheme,它不需要你加载jQuery!