如果一上来就加载页面中所有的数据,并渲染所有页面中的内容,必然发送很多次无效的请求,所以为了提高性能 我们使用可以懒加载的方式 等所在模块进入到 可视区域 在发送请求获取数据 ,这里我们使用的是`@vueuse/core` 中的`useIntersectionObserver` 来实现监听组件进入可视区域的行为
首先我们试着分析一些useIntersectionObserver 函数
import { useIntersectionObserver } from '@vueuse/core'
const { stop } = useIntersectionObserver(
target,
([{ isIntersecting }], observerElement) => {
targetIsVisible.value = isIntersecting
}
)
- stop 一个可执行的函数用来停止监听行为
- target 一个由ref api调用之后形成的RefImpl对象 也可以是一个dom对象
- isIntersecting 一个类型为布尔值的数据 当被监听元素进入视口区域时为true,离开视口区域时为false
- observerElement 被观察的dom
- 特别注意: 对于目标target是否进入视口区域的监听会一直进行不会只监听一次
组件数据懒加载
当进入可是区域的时候 在加载可视区域内的数据--画个简图 希望能有助于理解吧 画的不好 见谅。---页面区域既是你可以看到的可视区域
在公共组件内定义一个数据懒加载的函数
我这里是定义在了文件compositions内,
import { useIntersectionObserver } from '@vueuse/core'
import { ref } from 'vue'
export function useObserver (apiFn) {
const target = ref(null)
const { stop } = useIntersectionObserver(
// target 是观察的目标dom容器,必须是dom容器,而且是vue3.0方式绑定的dom对象
target,
// isIntersecting 是否进入可视区域,true是进入 false是移出
// observerElement 被观察的dom
([{ isIntersecting }], observerElement) => {
// 在此处可根据isIntersecting来判断,然后做业务
//会打印true 或者false
console.log(isIntersecting, 888)
if (isIntersecting) {
stop()// 关闭监听
// apiFn && apiFn()
if (apiFn) {
apiFn()
}
}
}
)
return target
}
引入 通过ref属性获得组件实例并测试
如果不在使用数据懒加载的那个区域 就打印false 到你使用数据懒加载的区域了 会打印true
import { useObserver } from '../../../compositions'
使用
export default {
name: 'HomeHot',
components: {
HomePanel
},
setup () {
const panelhotLlist = ref([])
//是我用来获取数据的函数--在dom元素操作区域不进行展示
const paneLists = async () => {
const res = await reqFindHot()
panelhotLlist.value = res.result
}
const target = useObserver(paneLists)
// const target = useObserver(数据接口-获取数据的那个函数)
return {panelnewList, target }
}
}
在操作dom的区域 通过ref属性获得组件实例并测试
HomePanel是我们定义的一个组件,这里需要使用你们自己组件
<template>
<!-- 和模板关联 -->
<HomePanel ref="target" title="123" subTitle="123123123">
.....
</HomePanel>
</template>
这样 一个组件数据懒加载就完成了。。
图片懒加载
图片懒加载 需要封装一个自定义指令 下面一起说了吧
- 首先看一下vue2 和 vue3 封装自定义指令的区别
// vue2
Vue.directive(指令名, {
inserted (el, binding) {
}
})
// vue3
app.directive(指令名, {
// 指令所在的元素,dom结构被解析完成
mounted (el, binding) {
}
})
使用 v3 封装自定义指令v-imgLazy
- 核心思路:监听图片是否进入到可视区域 正式进入可视区域之后将图片url数据交给img标签的src属性
- 我是在direcives文件夹中 以插件的方式 全局注册指令插件
//导入一个 默认图片路径 用做默认显示的图片
import defaltImg from '@/assets/images/200.png'
// 引入监听是否进入视口
import { useIntersectionObserver } from '@vueuse/core'
export default {
// 需要拿到main.js中由createApp方法产出的app实例对象
install (app) {
// app实例身上有我们想要的全局注册指令方法 调用即可
app.directive('imgLazy', {
mounted (el, binding) {
// el:img dom对象
// binding.value 图片url地址
// 使用vueuse/core提供的监听api 对图片dom进行监听 正式进入视口才加载
// img.src = url
console.log(el, binding)
const { stop } = useIntersectionObserver(
// 监听目标元素
el,
([{ isIntersecting }], observerElement) => {
if (isIntersecting) {
// 当图片url无效加载失败的时候使用默认图片替代
el.onerror = function () {
el.src = defaltImg
}
el.src = binding.value
stop()
}
})
}
})
}
}
- 在mian.js中注册插件
// 全局注册自定义指令
import directivesPlugin from '@/directives'
createApp(App)
.use(directivesPlugin)
.mount('#app')
- 在需要使用的地方使用即可 样式如下
<img v-imgLazy="item.picture" alt="" />