乐趣区

Javascript零碎之IntersectionObserver

IntersectionObserver 主要用于元素可见性的监听,比传统通过全局监听 scroll 事件去判断可见性无论是性能还是便利性都要好得多。因为 api 比较新,存在兼容性问题,好在已经有了兼容的 polyfill. 其基本介绍和使用方式都可以在该 polyfill 对应网站上看到。这里主要通过例子的形式,说明其实用的场景。

图片懒加载

之前的方式

以前我们实现图片懒加载的原理是这样的:

window.addEventListener('scroll', lazyload);
function lazyload() {const imgs = document.querySelector('.img');
    const innerHeight = util.innerHeight();
    const scrollTop = util.scrollTop();

    imgs.forEach((img) => {const imgOffsetH = util.getPosition(img).top;

        // 距离页面顶部的距离 <= 视窗高 + 往上滚进去的距离
        if(imgOffsetH <= innerHeight + scrollTop) {img.src = img.getAttribute('data-src');
        }
    })
}

条件是: 距离页面顶部的距离 <= 视窗高 + 往上滚进去的距离,即算做图片可见了才加载它。问题是这种通过监听 scroll 的方式很容易导致性能问题,或者多多少少会有些性能损失。

IntersectionObserver 的方式

const io = new IntersectionObserver((entrys) => {entrys.forEach((img) => {if(!img.isIntersecting) return;
        img.src = img.getAttribute('data-src');
        io.unobserve(img);
    })
}, {
      // 即滚动到距离底部 50px 时开始算交互区
       rootMargin:'0px 0px 50px 0px'
})
imgs.forEach((img) => {io.observe(img);
})

非常的清晰和简单,而且由于是原生的功能,不会引起性能损耗。这里的 rootMargin 参数非常好用,因为一般情况下的交互条件都需要添加一定的阈值,以实现更优雅和流畅的体验,而通过 rootMargin 能非常简单的实现这点。

完整示例请参考 lazyload.html

滚动分页

以前的方式

通过判断滚动是否到底部,即 视窗高+往上滚进去的距离 >= 页面高,来作为加载新的一页的条件:

window.addEventListener('scroll', () => {const innerHeight = util.innerHeight();
    const scrollTop = util.scrollTop(); 
    const scrollHeight = util.scrollHeight();
    // 滚动到距离底部 50px
    if(innerHeight + scrollTop >= scrollHeight - 50) {loadMore();
    }
});

IntersectionObserver 的方式

在最底部设置一个加载更多的标记器,监听它是否出现,作为加载新页的条件:

const io = new IntersectionObserver((entrys) => {entrys.forEach((entry) => {if(!entry.isIntersecting) return;
        loadMore();})
}, {rootMargin:'0px 0px 50px 0px'})
// 监听最底部的 loadmore 是否出现
const lMore = document.querySelector('.load-more');
io.observe(lMore);

在性能上仍然更胜一筹,而且不必每次都去判断视窗高、滚进去的距离等等,将以往很麻烦的事情变得简单而快捷。

完整示例请参考 paging.html

通过上面的两个例子,基本能了解 IntersectionObserver 的功能实用场景,即监听元素的出现,实现懒加载 (可以是图片、模版、甚至组件等等)、元素进出动画、分页等各种形式的功能。这对优化整个页面的性能还是非常有帮助的,所以在日常的项目中还是很值得尝试。

退出移动版