本文由Simon Codrington和Tim Severien进行了同行评审。 感谢所有SitePoint的同行评审人员使SitePoint内容达到最佳状态!
最近,一个有趣的新客户端JavaScript API出现在Web平台IntersectionObserver API上 。
这个微小但有用的API提供了一种手段,可以有效地监视(观察)指定DOM元素的可见性,即当它们在视口(浏览器窗口或元素的视口)内或外时。 可以精确指定元素可见性的定义,指定与视口矩形相交的元素区域的比例。
此功能的一些常见应用程序和用例包括:
- 内容的延迟加载
- 无限滚动
- 广告可见度
- 滚动触发的动画( 注意:这不是目标用例。API报告的可见性信息可能会略有延迟,并且不能保证像素完美的数据)。
浏览器支持
作为一个相当新的API,在撰写本文时,它的支持仍然很有限 :
- Chrome桌面51
- 适用于Android的Chrome 51
- Android WebView 51
- 歌剧38
- 适用于Android的Opera 38
但是, Github上提供了开发中的polyfill(不支持根边距),因此我们现在就可以开始使用Intersection Observers。
在本文中,我们将实现无限滚动UX模式。 我们将沿途使用上述的polyfill甚至几个ES6 / ES2015功能,例如promise,模板字符串和箭头功能。
无限滚动
想象一下,我们有一个长长的项目列表,我们想通过无限滚动浏览这些项目,以便当用户接近文档的底部时,下一批项目将被加载并追加到列表的末尾。
这是我们将要构建的:
请参阅CodePen上的SitePoint ( @SitePoint )的笔无限滚动演示 。
以下代码段中将开发的核心思想是,使用列表底部附近的一个项目,以及文档底部附近的一个项目,作为标记 ,表明何时浏览器视口即将接近浏览器视口。页。
该标记将是由IntersectionObserver
实例监视的DOM元素。 当此对象报告前哨可见性时,我们知道该加载下一组项目了。 一旦将它们加载,渲染并添加到列表中,我们将为下一页选择一个新的标记。
设置页面
因此,让我们从HTML开始。 页面正文标记只是一个列表:
<ul class="listview"></ul>
通常,此列表应该已经填充了第一项,但是为了简化代码,这些项将从JavaScript中获取,就像滚动时加载的连续页面一样。
然后,我们包括polyfill。 在实际情况下,只有在必要时才可以加载它。 我们甚至检查是否支持该API在屏幕上显示通知:
<span class="polyfill-notice">The polyfill is in use</span>
<script>
if (!('IntersectionObserver' in window))
document.body.classList.add('polyfill');
</script>
<script src="../intersectionobserver-polyfill.js"></script>
关于CSS,我们主要使用一些规则来设置列表视图的布局并设置支持通知的样式。 因为这不是本文的范围,所以请参考样式表以获取详细信息。
创建脚本
我们首先实例化一个IntersectionObserver
对象。 我们只需要一个实例,因为它将用于监视所有哨兵:
sentinelObserver = new IntersectionObserver(sentinelListener, {threshold: 1})
在第二个参数中传递的配置对象中,我们将可见性阈值(可见的元素区域的分数)设置为1
以仅在项完全位于视口内时触发事件侦听器(作为第一个参数传递)。 出于演示目的,哨兵元素以橙色边框标识。
事件监听器将执行我们上面概述的操作。 在查看其代码之前,让我们介绍一个对象来表示和管理当前的哨兵元素:
sentinel = {
el: null,
set: function(element) {
this.el = element;
this.el.classList.add('sentinel');
sentinelObserver.observe(this.el);
},
unset: function() {
if (!this.el)
return;
sentinelObserver.unobserve(this.el);
this.el.classList.remove('sentinel');
this.el = null;
}
}
这里最相关的行是调用IntersectionObserver
方法observe()
和unobserve()
来附加和分离要监视的元素的地方。
现在,事件侦听器可以使用此帮助器对象删除当前标记,在列表底部设置加载指示器,并使用nextPage
方法加载下一个列表页面。 这将加载,渲染和附加新项目。 它返回一个Promise来指示这些操作何时完成。 那时我们可以选择新的哨兵物品并关闭加载指示器:
sentinelListener = function(entries) {
console.log(entries);
sentinel.unset();
listView.classList.add('loading');
nextPage().then(() => {
updateSentinel();
listView.classList.remove('loading');
});
}
updateSentinel
方法选择下一个哨兵,选择新加载的页面的第一项:
updateSentinel = function() { sentinel.set(listView.children[listView.children.length - pageSize]);
}
其余代码主要包含nextPage
函数的实现。 解决了loadNextPage()
(模拟网络请求)返回的承诺后,所提供的item对象将以HTML呈现并附加在列表的末尾。
就是这样! 返回演示,以查看所有代码片段组装在一起。
进一步阅读
以下是一些指向更详尽文档的参考链接,涵盖了API及其基本原理:
您是否希望很快看到更多浏览器实现IntersectionObserver API?