最近在项目中,遇到要对大量图表数据渲染的状况。因此当时想着能不能只渲染视图中可见的图表呢?而后在网上搜索了一番,查到了这个有趣的知识。css
为开发者提供了一种能够异步监听目标元素与其祖先或视窗(viewport
)交叉状态的手段。祖先元素与视窗(viewport
)被称为根(root
)。html
let io = new IntersectionObserver(callback, options)
`callback` 是当元素的可见性变化时候的回调函数,`options`是一些配置项(可选)。
复制代码
options 主要有如下一个配置项。vue
const options = {
root: null,//表示默认为窗口
threshold: [0, 0.5, 1],//表示当观察元素出现0%、50%、100%时候就会触发回调函数
rootMargin: '30px 100px 20px'//
}
var io = new IntersectionObserver(callback, options)
复制代码
root
threshold
[0]
。threshold: [0,0.5,1],//表示当观察元素出现0%、50%、100%时候就会触发回调函数
复制代码
rootMargin
css
的定义方法。rootMargin: '10px 130 100px 50px'
//表示`top、right、bottom` 和 `left` 的值。
复制代码
callback在元素的可见性变化时,才会触发。
callback
中有一个参数 entries
。它是一个IntersectionObserverEntry
对象数组。以下图所示。主要有如下属性。咱们经常关注的有 isIntersecting
(表示当前是否可见)和 target
(被观察的目标元素)以及intersectionRatio
(表示元素的可见程度,0表示刚刚可见,1
表示彻底可见)。git
disconnect()
unobserve()
observe()
takeRecords()
如下是项目中的一部分html
代码,为了接下来更好的展现说明。github
<grid-layout :layout.sync="layout" :row-height="rowHeight" :is-draggable="draggable" :is-resizable="resizable" :is-mirrored="mirrored" :prevent-collision="preventCollision" :vertical-compact="true" :use-css-transforms="true" :responsive="responsive" @layout-mounted="layoutMountedEvent" @layout-updated="layoutUpdatedEvent">
<grid-item v-for="item in layout" :key="item.i" :static="item.static" :x="item.x" :y="item.y" :w="item.w" :h="item.h" :i="item.i" class="grid-item" :index="item.i" @resized="resized">
<Chart :optionData="item.data" :index='item.i' :type="item.displayType" @gridItemAllMounted="gridItemAllMountedEvent" />
</grid-item>
</grid-layout>
复制代码
接下来是在项目中用于条件渲染的核心代码。数组
//表示全部的Chart组件都被渲染好了,此时开始监听元素
function Observer(){
const callback = (entries) => {
entries.forEach(item => {
//index是我在目标元素上的一个自定义属性
const index = item.target.getAttribute('index');
if (item.isIntersecting) {
//将当前视图中可见的echart图进行渲染
this.$store.commit('initChart', index)
// this.io.unobserve(item.target); // 中止观察当前元素 避免不可见时候再次调用callback函数
} else {
// 清除不可见的,目的是为了避免渲染不在视图中的图片
this.$store.commit('clearInvisibleChartInstance', index)
}
});
}
this.io = new IntersectionObserver(callback);
const gridItems = document.querySelectorAll('.grid-item');
gridItems.forEach(item => {
this.io.observe(item);
});
}
复制代码
在这个项目中主要有如下几点须要注意。浏览器
grid-layout
组件的宽度来均分 gridItem
,因此须要等到计算出 grid-layout
时才能对它的子组件进行平均分配。因此有如下的代码。//gridLayout组件编译好后(Mounted()),在上级组件中触发的监听函数,此时才开始根据gridLayout组件均配gridItem的宽度。
layoutMountedEvent (colNum) {
this.colNum = colNum
this.createLayoutData(this.colNum)
}
复制代码
//全部的`echart组价渲染完毕后触发`
gridItemAllMountedEvent () {
this.startObserver()
},
复制代码
isIntersecting
属性。item.target
是全部的目标元素。而在后面利用滚动条来操做时的 item.target
就是要显示和要隐藏的元素。因此能够利用这个性质。能够用一个对象来实时保存当前可见的元素。当窗口变化时,就能够额作到真正的条件渲染了。entries.forEach(item => {
//index是我在目标元素上的一个自定义属性
const index = item.target.getAttribute('index');
if (item.isIntersecting) {
//将当前视图中可见的echart图进行渲染
this.$store.commit('initChart', index)
// this.io.unobserve(item.target); // 中止观察当前元素 避免不可见时候再次调用callback函数
} else {
// 清除不可见的,目的是为了避免渲染不在视图中的图片
this.$store.commit('clearInvisibleChartInstance', index)
}
});
复制代码
项目地址bash