背景介绍:
随着当前项目的越来越大,某些界面的模块越来越多了,导致进入页面的加载速度很满。所以想做个界面的懒加载,加快一下进入界面的速度。
界面可能像下面这样。要实现模块的懒加载
怎么实现
思路
所有模块在初始化的时候先不调用初始化的方法。加载一个简单的静态页面。
在内容区域的mounted方法里面的添加IntersectionObserver方法,去监听个个模块是否在可视区域,如果在就初始化模块,取消监听,防止多次初始化。
IntersectionObserver介绍
IntersectionObserver是一个用来判断两个元素是否重叠的api。
支持两个参数IntersectionObserver(callback, options)。callback是监听元素的可见性变化时触发的回调函数;options是配置参数,可选。
callback参数
//observer 回调函数
const observerCallback = (entries) => {
entries.forEach(item => {
/*
* item.time当可视状态变化时,状态发送改变的时间戳,ms
* item.rootBounds:根元素矩形区域的信息,即为getBoundingClientRect方法返回的值
* item.boundingClientRect:目标元素的矩形区域的信息。
* item.intersectionRect:目标元素与视口(或根元素)的交叉区域的信息.
* item.isIntersecting:目标元素与根元素是否相交
* item.intersectionRatio:目标元素的可见比例,即intersectionRect占boundingClientRect的比例。
* item.target:目标元素。
*/
})
}
options配置:
{
root //表示监听的可视区域dom,默认为body
threshold //目标元素与视窗重叠的阈值(0~1)
rootMargin // 类似于margin,可以加大root的区域
}
整体实现
父级元素
<template>
<div ref="moduleMain">
<ModuleItem></ModuleItem>
<ModuleItem></ModuleItem>
<ModuleItem></ModuleItem>
<ModuleItem></ModuleItem>
<ModuleItem></ModuleItem>
<ModuleItem></ModuleItem>
<ModuleItem></ModuleItem>
<ModuleItem></ModuleItem>
<ModuleItem></ModuleItem>
</div>
</template>
<script>
import ModuleItem from "./ModuleItem.vue";
export default {
name: "intersectionObserverTest",
components: {
ModuleItem,
},
data() {
return {};
},
mounted() {
// 获取所有待观察的目标元素
let headers = this.$refs.moduleMain.querySelectorAll(".module-item");
var options = {
threshold: 0.5, //目标元素与视窗重叠的阈值(0~1)
root: null, // 目标视窗即目标元素的父元素,如果没有提供,则默认body元素
};
function lazyLoad(target) {
const observer = new IntersectionObserver((entries, observer) => {
entries.forEach((entrie) => {
if (entrie.isIntersecting) {
const head = entrie.target;
head.__vue__.init();
observer.unobserve(head); // 停止监听已加载的模块,防止多次加载
}
});
}, options);
observer.observe(target);
}
headers.forEach(lazyLoad);
},
};
</script>
子元素
<template>
<div class="module-item">2222</div>
</template>
<script>
export default {
name: "ModuleItem",
data() {
return {};
},
methods: {
init() {
console.log('当前在视图范围内,初始化界面');
}
}
}
</script>
<style scoped>
.module-item {
width: 100%;
height: 300px;
}
</style>
关键地方讲解
// 获取所有待观察的目标元素,这里所有的dom都有相同的class,用这个来获取
let headers = this.$refs.moduleMain.querySelectorAll(".module-item");
var options = {
threshold: 0.5, //目标元素与视窗重叠的阈值(0~1)
root: null, // 目标视窗即目标元素的父元素,如果没有提供,则默认body元素
};
function lazyLoad(target) {
const observer = new IntersectionObserver((entries, observer) => {
entries.forEach((entrie) => {
// isIntersecting代表是否相交,这里表示到视口区域内了
if (entrie.isIntersecting) {
const head = entrie.target;
// head为dom,需要用__vue__才能调用内部方法,可以打debugger看看
head.__vue__.init();
observer.unobserve(head); // 停止监听已加载的模块,防止多次初始化
}
});
}, options);
observer.observe(target);
}
headers.forEach(lazyLoad);
最终效果
随着界面的滚动,下放的模块触发初始化事件,实现懒加载。