Vue项目性能优化之—自定义指令实现图片懒加载、首屏渲染优化(组件数据懒加载)、vue-lazyload的使用
vue-lazyload实现图片懒加载
1 安装 vue-lazyload
npm i vue-lazyload -S
2 在 main.js 中进行引用
-
import VueLazyload from "vue-lazyload"; Vue.use(VueLazyload)
3 自定义配置插件
-
Vue.use(VueLazyload,{ // 设置相应的 loading 图和图片错误显示图 error: require('@/assets/lazy/error.png'), loading: require('@/assets/lazy/loading.gif'), attempt: 1, // 尝试加载图片数量 // try: 2 // 加载图片数量 })
4 使用
-
单图
-
<img v-lazy ='图片地址' :key='图片地址'>
-
-
多图
-
<div v-lazy-container="{ selector: 'img' }"> <img data-src="图片地址"> <img data-src="图片地址"> <img data-src="图片地址"> <img data-src="图片地址"> </div>
-
- ❗✨注:
- 背景图片中使用懒加载
v-lazy:background-image = ''
要注意图片和盒子大小问题
- 使用时可以添加一个 key 属性
- 背景图片中使用懒加载
补充
属性 | 作用 | 默认值 | 类型 |
---|---|---|---|
preLoad | 预加载高度比例 | 1.3 | Number |
error | 图片路径错误时加载图片 | 'data-src' | String |
loading | 预加载图片(占位图片) | 'data-src' | String |
attempt | 尝试加载图片数量 | 3 | Number |
自定义指令实现图片懒加载
实现原理:
先储存图片地址 不能先放在src上(放在src上直接发请求了) 当图片进入可视区 将src地址换成存储地址
IntersectionObserver介绍
实现步骤
-
app.directive() 传入自定义指令的名称和配置
-
当使用指令的DOM创建好后,创建一个观察对象 来观察当前使用指令的元素并开始观察
-
当进入可视区后停止观察
-
把指令的值设置给 el 的 src 属性 ( binding.value 就是指令的值 )
-
处理图片加载失败 error是图片加载失败的事件 加载失败后设置默认图 load是图片加载成功
代码实现
基于vue2.0和 IntersectionObserver封装懒加载指令
// 图片地址(可通过
import defaultImg from '@/assets/images/200.png'
// 定义指令
const defineDirective = (Vue) => {
// 1.图片懒加载 v-lazy 指令directive
Vue.directive('lazy', {
// 监听使用指令的DOM是否创建好
// el -->传入的dom binding --->传入的图片路径
inserted(el,binding) {
// 2.创建一个观察对象 来观察当前使用指令的元素
const observe = new IntersectionObserver(([{isIntersecting}]) => {
if (isIntersecting) {
// 进入可视区
// 停止观察
observe.unobserve(el)
// 3.把指令的值设置给el的src属性 binding.value 就是指令的值
// 4.处理图片加载失败 error是图片加载失败的事件 load是图片加载成功
el.onerror = () => {
// 加载失败 设置默认图
el.src = defaultImg
}
el.src = binding.value
}
}, {
threshold:0.01
})
// 开启观察
observe.observe(el)
},
})
}
export default{
install(Vue){
defineDirective(Vue)
}
}
基于vue3.0和 IntersectionObserver封装懒加载指令
import defaultImg from '@/assets/images/200.png'
// 定义指令
const defineDirective = (app) => {
// 1.图片懒加载 v-lazy 指令directive
// 原理:先储存图片地址 不能先放在src上(放在src上直接发请求了) 当图片进入可视区 将src地址换成存储地址
app.directive('lazy', {
// 监听使用指令的DOM是否创建好
// el -->传入的dom binding --->传入的图片路径
mounted(el,binding) {
// 2.创建一个观察对象 来观察当前使用指令的元素
const observe = new IntersectionObserver(([{isIntersecting}]) => {
if (isIntersecting) {
// 进入可视区
// 停止观察
observe.unobserve(el)
// 3.把指令的值设置给el的src属性 binding.value 就是指令的值
// 4.处理图片加载失败 error是图片加载失败的事件 load是图片加载成功
el.onerror = () => {
// 加载失败 设置默认图
el.src = defaultImg
}
el.src = binding.value
}
}, {
threshold:0.01
})
// 开启观察
observe.observe(el)
},
})
}
export default {
install (app) {
defineDirective(app)
}
}
首屏渲染优化(组件数据懒加载)
实现原理:
当模块进入到 可视区 ,再发请求获取数据
检测目标元素的可见性
任务目标:
了解如何检测目标元素的可见性
技术方案:
我们可以使用 @vueuse/core
中的 useIntersectionObserver
来实现监听组件进入可视区域行为,需要配合 vue3
的组合 API
的方式才能实现
先分析下这个useIntersectionObserver 函数:
🔔核心单词解释:
- useIntersectionObserver 检查元素是否进入可视区函数
- target 目标元素,🎯需配合模板 ref 使用
- isIntersecting 是否进入可视区(布尔值)
- stop 用于停止检测的函数
<script setup lang="ts">
import { ref } from 'vue';
import { useIntersectionObserver } from '@vueuse/core';
// 准备目标元素(DOM节点或组件,需配合模板 ref 使用)
const target = ref(null);
const { stop } = useIntersectionObserver(target, ([{ isIntersecting }]) => {
console.log('检测元素可见性', isIntersecting);
// 需求:如果目标元素进入可视区,就发送请求,并停止检测
if (isIntersecting) {
// 当目标元素进入可视区域时,才发送请求
console.log('进入可视区,需要发送请求');
// 请求已发送,主动停止检查
stop();
}
});
</script>
<template>
<div style="height: 2000px"></div>
<!-- 🎯目标元素需添加模板 ref -->
<div ref="target">
<h1>🎯我是目标元素🎯</h1>
</div>
<div style="height: 2000px"></div>
</template>
我们以新鲜好物模块为例演示一下这个函数的使用方式
1)通过 ref
属性获得组件实例并测试
2)使用useIntersectionObserver
监听函数
<script setup lang="ts">
import HomePanel from "./home-panel.vue";
import { ref } from "vue";
import { useIntersectionObserver } from "@vueuse/core";
import useStore from "@/store";
const { home } = useStore();
// 通过 ref 获得组件实例
const target = ref(null);
const { stop } = useIntersectionObserver(
// target 被检测的目标元素
target,
// isIntersecting 是否进入可视区域
([{ isIntersecting }]) => {
// 在此处可根据isIntersecting来判断,然后做业务
console.log('是否进入可视区域', isIntersecting);
if (isIntersecting) {
home.getHotGoodsList();
stop();
}
}
);
</script>
<template>
<div class="home-hot">
<!-- 🚨 添加 ref="target" 和 模板关联 -->
<HomePanel ref="target" title="人气推荐" sub-title="人气爆款 不容错过">
...
</HomePanel>
</div>
</template>
3)测试效果
打开浏览器,人气推荐模块还未进入到可视区,打印值为false,
然后我们滑动页面,当人气模块
组件进入可视区中时,再次发生打印,此时为true,
到此我们就可以判断组件进入和离开可视区了
❗特别注意:每次被监听的dom进入离开可视区时都会触发一次,而不是只触发一次, 可以stop关闭监听