javascript - 如何确定子 iframe 元素何时在滚动 div 的可见区域内?
问题描述
我有一个滚动 div,它可能包含也可能不包含一个或多个 iframe,只有当 iframe 在父 div 的滚动区域的顶部和底部之间部分/完全可见时才应加载其内容。但是,当 div 中有 iframe 并且我在 Chrome 中检查我的网页时,我看到 iframe 的 offsetTop 值不会随着父 div 的滚动条向上或向下滚动而改变。另外,我看到 iframe 的 offsetParent 引用了 body 元素,而不是实际包含 iframe 的滚动 div。
这是一个简单的网页,显示了我正在谈论的基本 div 和嵌套 iframe 结构:
<!DOCTYPE html>
<html>
<body>
<!-- Scrolling div -->
<div id="scroller" style="height:316px; width: 322px; overflow-y:scroll;">
<!-- 5 iframes that each contain an img tag that is ignored -->
<iframe><img id="img" src="1.png"></iframe><br />
<iframe><img id="img" src="2.png"></iframe><br />
<iframe><img id="img" src="3.png"></iframe><br />
<iframe><img id="img" src="4.png"></iframe><br />
<iframe><img id="img" src="5.png"></iframe><br />
</div>
<script>
//
// Assign an onScroll function to the scroller div that monitors the div's
// scrolling ...
//
function scrollerDivScrolling() {
var div = scrollerDivScrolling.div;
//
// The following code only changes the div's background color when the
// div's scroll-bar is scrolled: white when less-than or 50px or
// yellow when more 50px.
//
if( div.scrollTop > 50 ) {
div.style.backgroundColor = "yellow";
}
else {
div.style.backgroundColor = "white";
}
//
// This is code needs to check each of the iframe's position to
// see if the iframe is displayed partially/fully between the
// parent div's scroll area's top and bottom, and if so then the
// iframe's content is set to the html statement(s) that are
// between to iframe's opening and closing tags. If the iframe's
// position is either completely above top of the parent div's
// scroll area or completely below the parent div's scroll area,
// then remove the contents.
//
}
scrollerDivScrolling.div = document.getElementById( 'scroller' );
scrollerDivScrolling.iframes = scrollerDivScrolling.div.getElementsByTagName( 'iframe' );
scrollerDivScrolling.div.onscroll = scrollerDivScrolling;
// Initialize the iframes with in the scroller div to 'show' their contents ...
for( var i = 0, iframes = scrollerDivScrolling.iframes, l = iframes.length, iframeDoc = null; i < l; ++i ) {
iframeDoc = iframes[ i ].contentWindow.document;
iframeDoc.open();
iframeDoc.write('Test' + ( i + 1 ) );
iframeDoc.close();
}
</script>
</body>
</html>
如上面的代码所示,iframe 实际上加载了“Test”后跟一个数字,而不是单个 iframe 标记中的图像标记语句,但这不是问题,因为我知道如何执行此操作已经。更重要的是,处理滚动 div 的 scrollerDivScrolling() 函数实际上并没有改变每个 iframe 的内容,具体取决于它相对于父 div 的滚动区域顶部和底部的位置,因为我还没有弄清楚每个 iframe 的哪些属性我需要使用的 iframe。
解决方案
我扩大了搜索范围,发现:Detect when elements within a scrollable div are out of view,我将其与我的 scrollerDivScrolling() 函数集成如下:
<script>
const UNDEFINED = undefined;
// Assign an onScroll function to the scroller div that monitors the div's scrolling ...
function checkInView( elem, partial ) {
var container = $( '.scrollable' );
var contHeight = container.height();
var contTop = container.scrollTop();
var contBottom = contTop + contHeight - 1;
var $elem = $( elem );
var elemTop = $elem.offset().top - container.offset().top;
var elemBottom = elemTop + $elem.height();
var isTotal = ( ( elemTop >= 0 ) && ( elemBottom <= contHeight ) );
var isPart = false;
if( partial ) {
isPart = ( ( ( elemTop < 0 ) && ( elemBottom > 0 ) ) || ( ( elemTop > 0 ) && ( elemTop <= container.height() ) ) );
}
return ( isTotal || isPart );
}
function scrollerDivScrolling() {
var div = scrollerDivScrolling.div;
for( var i = 0, iframes = scrollerDivScrolling.iframes, l = iframes.length, iframeDoc = null; i < l; ++i ) {
// If the element is in the scrollable div's visible area ...
if( checkInView( scrollerDivScrolling.iframes[ i ], true ) ) {
// If the element had not already been loaded ...
if( ( iframes[ i ].loaded === UNDEFINED ) || !iframes[ i ].loaded ) {
// Mark the element as loaded and load the element ...
iframes[ i ].loaded = true;
iframeDoc = iframes[ i ].contentWindow.document;
iframeDoc.open();
iframeDoc.write( 'Test' + ( i + 1 ) + ' ' + iframes[ i ].innerHTML );
iframeDoc.close();
}
}
else {
// Mark the element as NOT loaded and unload the element ...
iframes[ i ].loaded = false;
iframeDoc = iframes[ i ].contentWindow.document;
iframeDoc.open();
iframeDoc.write( '' );
iframeDoc.close();
}
}
}
scrollerDivScrolling.div = document.getElementById( 'scroller' );
scrollerDivScrolling.div.onscroll = scrollerDivScrolling;
scrollerDivScrolling.iframes = scrollerDivScrolling.div.getElementsByTagName( 'iframe' );
// Initialize the iframes with in the scroller div to 'show' their contents ...
for( var i = 0, iframes = scrollerDivScrolling.iframes, l = iframes.length, iframeDoc = null; i < l; ++i ) {
iframes[ i ].loaded = UNDEFINED;
}
scrollerDivScrolling();
</script>
对我来说,checkInView(...) 函数显示前三个 iframe 元素在滚动条一直位于顶部时处于“可见”状态,这意味着该函数对于 div 中的前三个元素返回 true,甚至虽然滚动 div 的高度仅足以显示前两个 iframe 元素,但这对我来说并不是问题。
使用这种技术,我可以“预加载”带有 html 的 iframe,当滚动 div 将每个 iframe 滚动到视图中时,它们将显示它们,并且每个 iframe 中包含的 img 标签通常会在它们进入视图时加载它们的图像。
对我来说,这有两个方面的帮助:初始页面加载不需要加载所有 iframe 之前可以查看页面,并且用户可以开始滚动浏览“行”iframe 子页面,以及结束包含所有数据所需的所有存储量都有些“扁平化”,因为仅加载了正在显示的元素所需的页面数据,并删除了可滚动 div 中的隐藏行。当它们的内容被替换为''。
这是一个 Pen 演示,展示了其工作原理的工作示例:Scrolling Div of delay-loading iframes
推荐阅读
- java - 多对一中的Spring未解决的前向引用
- mysql - 在 SQL 中选择部分匹配输入的行
- sql - 从 BigQuery 中具有无效令牌的列中解析 JSON 文件
- push-notification - Swift iOS 13:单击推送通知如何打开文本字段?
- testing - 如何让我的 TestCafe 框架处理 Web 应用程序上的 A/B 实验?
- java - OpenJDK 11 和 Eclipse 中的 javax.xml 问题
- asp.net-mvc - ASP.NET MVC 中同一视图/控制器上的多个操作
- reactjs - Moment.js 返回 RangeError:时间值无效
- laravel - 在 Laravel 项目中放置类的位置
- python - 使用 pandas 绘制系列或数据框,其 x 轴比可用的实际数据长