# 自定义指令封装
# v-once 指令
只渲染一次元素和组件,并且跳过以后的更新。
在随后的重新渲染,元素/组件及其所有子项将被当作静态内容并跳过渲染。这可以用来优化更新时的性能。
<script setup>
import {ref} from "vue";
const count = ref(0);
setInterval(() => {
count.value++;
}, 1000);
</script>
<template>
<span v-once>使它从不更新: {{ count }}</span>
</template>
# 使用自定义指令实现图片懒加载
自定义指令一般位于 main.js 中进行配置
//获取app实例
import {createApp} from "vue";
const app = createApp(App);
app.directive("img-lazy", {
//mounted 自定义指令绑定元素挂载完毕时触发
mounted(el, binding) {
//el 组件实例 自定义指令绑定的那个元素 img
//binding: 等于号指令表达式后面的值
console.log("自定义指令", el, binding.value);
// 使用vueuse提供的useIntersectionObserver方法判断当前绑定自定义指令的元素是否进入视口
useIntersectionObserver(el, ([{isIntersecting}]) => {
//isIntersecting 元素是否进入视口 布尔值
console.log("元素进入视口", isIntersecting);
//img标签在绑定src属性时会立即发送图片请求
if (isIntersecting) el.src = binding.value;
});
},
});
# 封装图片懒加载插件
- 在上述操作中,图片懒加载代码放在
main.js入口函数中,而入口函数只是负责页面初始化,不因该包含太多逻辑代码 - 可以通过插件的方法把懒加载指令封装为插件,
main.js入口函数只需要负责注册插件即可
- 项目 src 文件夹下新建
directives插件文件夹 在此文件夹中存放插件 - 编写懒加载插件
//引入vueuse中监听元素进入视口的方法
import {useIntersectionObserver} from "@vueuse/core";
//定义懒加载插件
export const lazyPlugin = {
//install函数 固定写法 参数为app实例
install(app) {
//懒加载指令逻辑
//自定义指令
app.directive("img-lazy", {
mounted(el, binding) {
//el 组件实例 自定义指令绑定的那个元素 img
//binding: 等于号指令表达式后面的值
const {stop} = useIntersectionObserver(el, ([{isIntersecting}]) => {
console.log("元素进入视口", isIntersecting);
if (isIntersecting) {
el.src = binding.value;
//图片加载完毕后停止监听
stop();
}
});
},
});
},
};
- 在 main.js 中注册插件
//引入懒加载指令并注册
import {lazyPlugin} from "@/directives";
app.use(lazyPlugin);
- 自定义指令的使用
<img v-img-lazy="item.picture" alt=""/>
# 监听元素宽高变化
//监听元素宽高变化
//创建元素数组
const map = new WeakMap()
//创建观察者
const ob = new ResizeObserver((entries) => {
for (const entry of entries) {
const handle = map.get(entry.target)
const box = entry.borderBoxSize[0]
if (handle) handle({width: box.inlineSize, height: box.blockSize})
}
})
export const resizePlugin = {
install(app) {
app.directive('resize', {
mounted(el, binding) {
//监听元素尺寸变化
ob.observe(el)
map.set(el, binding.value)
},
unmounted(el) {
ob.unobserve(el)
}
})
}
}
# 使用
<template>
<div v-resize='sizeChange'>监听元素尺寸变化</div>
</template>
<script lang="ts" setup>
//元素宽高变化的处理函数
const sizeChange = (value) => {
console.log('元素宽高变化', value)
}
</script>