背景
记一次造轮子的过程,我想大家都有做滚动加载的需求。用UI组件?自己监听滚动事件?用别人的UI组件,万一有坑呢?传统的监听滚动事件,事件密集,容易造成性能问题。所以在2020年的今天是不是可以来点不一样的~_~
目前有一个新的 IntersectionOberver API,可以自动"观察"元素是否可见,Chrome 51已经支持。由于可见(visible)的本质是,目标元素与视口产生一个交叉区,所以这个 API 叫做"交叉观察器"。(大概就是如下图,有个滑块在视口进进出出会被监听)
关于IntersectionObserver
//IntersectionObserver本身是一个构造函数
//传入的是一个callback函数,其中回调函数传入的参数是包含被监听对象信息的数组
new IntersectionObserver((change) => {
//do something...
//change是一个数组,每个都是IntersectionObserverEntry对象
})
1. IntersectionObserver.disconnect()
停止监听工作
2. IntersectionObserver.observe()
开始监听一个目标元素
3. IntersectionObserver.takeRecords()
返回所有被观察对象的数组(IntersectionObserverEntry)
4. IntersectionObserver.unobserve()
停止监听特定目标元素//IntersectionObserverEntry对象里面的属性(都是只读)
1. boundingClientRect 返回包含目标元素的边界信息的DOMRectReadOnly。边界的计算方式与 Element.getBoundingClientRect() 相同
2. intersectionRatio返回intersectionRect 与 boundingClientRect 的比例值
3. intersectionRect返回一个 DOMRectReadOnly 用来描述根和目标元素的相交区域
4. isVisible返回一个布尔值, 是否在该视口内可见
5. isIntersecting返回一个布尔值, 如果目标元素与交叉区域观察者对象(intersection observer) 的根相交,则返回 true.如果返回 true, 则 IntersectionObserverEntry 描述了变换到交叉时的状态; 如果返回 false, 那么可以由此判断,变换是从交叉状态到非交叉状态
6. rootBounds返回一个 DOMRectReadOnly 用来描述交叉区域观察者(intersection observer)中的根
7. target与根出现相交区域改变的元素 (Element)
8. time返回一个记录从 IntersectionObserver 的时间原点(time origin)到交叉被触发的时间的时间戳(DOMHighResTimeStamp)实战VUE滚动无限加载组件
<template>
<div class="scroll-tool" ref="scroll-tool">
<slot></slot>
<div class="loadStatus">
<span v-show="this.noMore">没数据了~</span>
<div v-show="!this.noMore&&loading">
加载中<Icon type="ios-loading" class="loadingAnimate"/>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'scroll-tool',
props:{
data: {type: Array,default: () => {}},
// 数据已经全部加载
noMore: {type: Boolean,default: false},
loading: {type: Boolean,default: false}
},
data () {
return {
nowOberver: ''
}
},
watch: {
data (value, oldVal) {
this.$nextTick(() => {
// 及时清空
this.nowOberver && this.nowOberver.disconnect()
this.nowOberver = new IntersectionObserver((change) => {
// 目标元素与交叉区域观察者对象相交时,还有数据需要加载时,没有正在加载数据
if (change[0].isIntersecting && !this.noMore && !this.loading) {
//change就是包含IntersectionObserverEntry对象的数组
// 继续加载
this.$emit('loadMore')
}
})
const list = this.$refs['scroll-tool'].children[0].children
this.nowOberver.observe(list[list.length - 1])
})
}
},
}
</script>
<style scoped lang="less">
.scroll-tool{
.loadStatus{
font-size: 14px;
display: flex;
justify-content: center;
align-content: center;
padding: 10px 0;
}
.loadingAnimate{
animation: animal 1s infinite linear ;
-webkit-animation: animal 1s infinite linear ;
-webkit-transform-origin: center center;
-ms-transform-origin: center center;
transform-origin: center center;
}
}
//loading Icon的无限旋转动画
@keyframes animal
{
0%{
transform: rotate(0deg);
-ms-transform: rotate(0deg);
-webkit-transform: rotate(0deg);
}
100%{
transform: rotate(360deg);
-ms-transform: rotate(360deg);
-webkit-transform: rotate(360deg);
}
}
</style>其他运用
大家点外卖的时候,可以观察到美团这个页面做的处理。也可以用这个做哟~~