1、何为组件数据懒加载?
前言
电商项目核心优化技术手段:组件数据懒加载 (首屏渲染优化)
电商类网站,首页内容有好几屏,如果一上来就加载所有屏的数据,并渲染所有屏的内容,必然发送很多次无效的请求,我们应该等所在模块进入到 可视区
再发请求获取数据。
思考
- 我们一般的数据请求在哪里发起?
setup
(created) - 生命周期钩子函数的特点是什么? 一加载组件,就立刻执行
结论
我们希望组件正式进入到 可视区
中时,才把组件内部的 ajax
请求发起,否则不请求数据,那如何判断进入可视区,并进行组件数据懒加载呢?
2、如何判断组件进入可视区?
技术方案
我们可以使用 @vueuse/core
中的 useIntersectionObserver来实现监听组件进入可视区域行为,
需要配合 vue3.0
的组合 API
的方式才能实现
分析useIntersectionObserver
函数:
// 下包 npm i @vueuse/core@5.3.0 或 yarn add @vueuse/core@5.3.0
// 导入 useIntersectionObserver 函数
import { useIntersectionObserver } from '@vueuse/core'
// 1.stop 一个可执行的函数用来停止监听行为
// 2.target 一个由 ref api 调用之后形成的 RefImpl 对象 也可以是一个 dom 对象
// 3.isIntersecting 一个类型为布尔值的数据 当被监听元素进入视口区域时为 true ,离开视口区域时为 false
// 4.observerElement 被观察的dom
const { stop } = useIntersectionObserver(
target,
([{ isIntersecting }], observerElement) => {
targetIsVisible.value = isIntersecting
}
)
// ◆特别注意: 对于目标target是否进入视口区域的监听会一直进行不会只监听一次,可以 stop() 关闭监听
复制代码
3、实现组件数据懒加载(代码落地)
- 通过
ref
属性获得组件实例并测试 - 使用
useIntersectionObserver
监听函数 - 发送的ajax请求在
isIntersecting
为true
时触发 - 一旦触发一次之后停止监听
stop()
,防止接口重复调用
<template>
<HomePanel ref="target" title="人气推荐" sub-title="人气爆款 不容错过">
<ul class="goods-list">
<li v-for="item in hotList" :key="item.id">
<RouterLink to="/">
<img :src="item.picture" alt="">
<p class="name">{{item.title}}</p>
<p class="desc">{{item.alt}}</p>
</RouterLink>
</li>
</ul>
</HomePanel>
</template>
<script>
// 导入子组件 HomePanel
import HomePanel from './home-panel'
// 导入获取数据的件接口函数
import { reqFindHot } from '@/api/home'
// 导入 ref 函数(使目标数据变成响应式数据)
import { ref } from 'vue'
// 导入 useIntersectionObserver 进行监听
import { useIntersectionObserver } from '@vueuse/core'
export default {
name: 'HomeHot',
components: { HomePanel },// 注册子组件
setup () {
const hotList = ref([])
const getHotList = async () => {
const res = await reqFindHot()
hotList.value = res.result
}
// getHotList()
// 1.通过 ref 获得组件实例
const target = ref(null)
// 2.使用 useIntersectionObserver 监听函数
const { stop } = useIntersectionObserver(
target,// 3.target 是被观察的目标dom容器
([{ isIntersecting }], observerElement) => {
// 4.在此处可根据 isIntersecting 来判断,然后做处理
console.log(isIntersecting)
// 5.如果 isIntersecting 为 true
if (isIntersecting) {
stop()// 6.中止监听
getHotList()// 7.调用函数(发送请求)
}
}
)
// 8.把 target 返回
return { hotList, target}
}
}
</script>
复制代码
4、组件数据懒加载的逻辑复用
事实上,首页中有很多地方都应该使用 组件数据懒加载 这个功能,不管是哪个模块使用,下面代码都会重复书写,可能会随着业务使用发生变化的是 ajax
接口的调用,其余的部分我们进行重复使用,抽离为可复用逻辑。
下面,我们将以上代码抽离出来进行复用:
新建 src/compositions/index.js
// ◆封装组件懒加载的函数
import { ref } from 'vue'
import { useIntersectionObserver } from '@vueuse/core'
// 按需导出
export function useObserver (apiFn) {// apiFn 为形参
const target = ref(null)
const { stop } = useIntersectionObserver(
target,
([{ isIntersecting }], observerElement) => {
console.log(isIntersecting, '666')
if (isIntersecting) {
stop()// 终止监听
apiFn && apiFn()
}
}
)
return target// 一定要 return 出去
}
复制代码
在需要的页面调用
<template>
<HomePanel ref="target" title="人气推荐" sub-title="人气爆款 不容错过">
<ul class="goods-list">
<li v-for="item in hotList" :key="item.id">
<RouterLink to="/">
<img :src="item.picture" alt="">
<p class="name">{{item.title}}</p>
<p class="desc">{{item.alt}}</p>
</RouterLink>
</li>
</ul>
</HomePanel>
</template>
<script>
import HomePanel from './home-panel'
import { reqFindHot } from '@/api/home'
import { ref } from 'vue'
// import { useIntersectionObserver } from '@vueuse/core'
// 1.按需导入封装好的组件懒加载函数
import { useObserver } from '@/compositions'
export default {
name: 'HomeHot',
components: { HomePanel },
setup () {
const hotList = ref([])
const getHotList = async () => {
const res = await reqFindHot()
hotList.value = res.result
}
// 2.调用封装好的函数,传实参过去
const target = useObserver(getHotList)
// getHotList()
return { hotList, target }
}
}
</script>
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END