
Intersection Observer API提供了一种异步观察目标元素与祖先元素或顶级文档viewport的交集中的变化的方法
这个api可以干什么?
当你需要知道可视区内容时候,它可以帮你做监听,相比滚动计算方法更加当高效。
应用场景
- 当页面滚动时,懒加载图片或其他内容。
- 实现“可无限滚动”网站,也就是当用户滚动网页时直接加载更多内容,无需翻页。
- 为计算广告收益,检测其广告元素的曝光情况。
- 根据用户是否已滚动到相应区域来灵活开始执行任务或动画。
下面会介绍:
- web端IntersectionObserver的用法
- 小程序端wx.createrInertersectionOberver
- Taro框架中统一api
web端使用方法
// 1. 创建observer对象
var options = {
root: document.querySelector('#scrollArea'),
rootMargin: '0px',
threshold: 1.0, // number[] | number 阀值( 范围在0.0-1.0之间 )
}
var observer = new IntersectionObserver(callback, options);
一旦IntersectionObserver被创建,则无法更改其配置,所以一个给定的观察者对象只能用来监听可见区域的特定变化值
阈值为1.0意味着目标元素完全出现在root选项指定的元素中可见时,回调函数将会被执行
// 2. 观察目标
var target = document.querySelector('#listItem');
observer.observe(target);
var callback = function(entries, observer) {
entries.forEach(entry => {
// Each entry describes an intersection change for one observed
// target element:
// entry.boundingClientRect
// entry.intersectionRatio
// entry.intersectionRect
// entry.isIntersecting
// entry.rootBounds
// entry.target
// entry.time
});
};
回调接收IntersectionObserverEntry对象和观察对象列表
小程序端使用方法
微信小程序API:wx.createIntersectionObserver
此api属于wxml中的方法,说明观察者是在视图线程中进行观察,回调函数在逻辑层触发
IntersectionObserver wx.createIntersectionObserver(Object component, Object options)
创建并返回一个 IntersectionObserver 对象实例。在自定义组件或包含自定义组件的页面中,应使用 this.createIntersectionObserver([options])来代替。
taro应用中使用 this.$scope.createIntersectionObserver([options])来代替
Page({
onLoad: function(){
wx.createIntersectionObserver({ thresholds: [1] })
.relativeToViewport({bottom: 100})
.observe('.target-class', (res) => {
res.intersectionRatio // 相交区域占目标节点的布局区域的比例
res.intersectionRect // 相交区域
res.intersectionRect.left // 相交区域的左边界坐标
res.intersectionRect.top // 相交区域的上边界坐标
res.intersectionRect.width // 相交区域的宽度
res.intersectionRect.height // 相交区域的高度
})
}
})
通过res.intersectionRatio > 0来判断观察目标是否出现在视图中,thresholds阀值要指定,以减少回调函数的触发,提高性能。
统一封装
在Taro项目中维护着H5项目和小程序项目,如果使用2个api,会造成逻辑冗余,不便于维护。所以提供了统一的api来使用
class AVisibleObserver {
constructor(targetDomId, rootDomId, component, onActiveChange) {
this.targetDomId = targetDomId
this.rootDomId = rootDomId
this.component = component
this.onActiveChange = onActiveChange
}
observe() { }
unobserve() { }
}
/**
* thresholds,触发阈值的集合数组,默认 [0],例:我配置了 [0, 0.5, 0.8],那么当监听对象和参照物相交比例达到 0 / 0.5 / 0.8 时,会触发监听器的回调函数
*/
class WeappIntersectionObserver extends AVisibleObserver {
constructor(targetDomId, rootDomId, component, onActiveChange) {
super(targetDomId, rootDomId, component, onActiveChange)
this.intersectionObserver = component.$scope
.createIntersectionObserver({ initialRatio: 0, thresholds: [0,1] })
.relativeToViewport({ top: 0, bottom: 0 })
}
observe() {
this.intersectionObserver.observe(this.targetDomId, entry => {
if( entry.intersectionRatio > 0 ){
this.onActiveChange(true)
}else {
this.onActiveChange(false)
}
})
}
unobserve() {
this.intersectionObserver.disconnect()
}
}
class WebIntersectionObserver extends AVisibleObserver {
constructor(targetDomId, rootDomId, component, onActiveChange) {
super(targetDomId, rootDomId, component, onActiveChange)
this.intersectionObserver = new IntersectionObserver(entries => {
if( entries[0].intersectionRatio > 0 ){
onActiveChange(true)
}else{
onActiveChange(false)
}
}, {
root: document.querySelector(rootDomId)
})
}
observe() {
if( document.querySelector(this.targetDomId) ){
this.intersectionObserver.observe(document.querySelector(this.targetDomId))
}
}
unobserve() {
this.intersectionObserver.disconnect()
}
}
class VisibleObserver extends AVisibleObserver {
constructor(targetDomId, rootDomId, component, onActiveChange) {
super(targetDomId, rootDomId, component, onActiveChange)
if (process.env.TARO_ENV === 'h5') {
this.actualVisibleObserve = new WebIntersectionObserver(targetDomId, rootDomId, component, onActiveChange)
} else {
this.actualVisibleObserve = new WeappIntersectionObserver(targetDomId, rootDomId, component, onActiveChange)
}
}
observe() {
this.actualVisibleObserve.observe()
}
unobserve() {
this.actualVisibleObserve.unobserve()
}
}
function createVisibleObserver({ targetDomId, rootDomId, component }, onActiveChange){
const visibleObserver = new VisibleObserver(targetDomId, rootDomId, component, onActiveChange)
visibleObserver.observe()
return visibleObserver
}
export default createVisibleObserver
this._observer = createVisibleObserver({
targetDomId,
rootDomId: '#app',
component: this
}, onActiveChange)
polyfill
