前言
自定义指令真的蛮好用,尤其是一些繁琐的很多组件都通用的监控,直接扔到指令里面就行。但是从vue2到vue3的演进过程里,指令的使用方式发生了比较大的变化,而且有一些坑,在这里记录一下。
- Tips:本文默认你已经熟练使用vue2的自定义指令
从一个需求开始
需求:前端项目使用element-ui,其中el-table的表高在换不同显示屏的时候很难适配,需要一个统一的处理手段进行自适应,应该怎么做呢?
第一阶段
手动设定两三种表高,监听判断屏幕大小,然后匹配一下。这个实在太low,直接放弃
第二阶段
我最初的想法是写一个setInterval,每隔1秒钟扫一次document.clientHeight,来判断表高是否需要调整,代码如下:
setInterval(() => {
const h = document.documentElement.clientHeight
if(h !== oldHeight.value) {
tableHeight.value = h * 0.6
oldValue.value = h
}
}, 1000)
但是这个有问题,每个需要调整表高的组件都要写一个监听,太繁琐且难以维护。放弃该方案
第三阶段
我们的directive闪亮登场。
自定义指令的注册
const app = Vue.createApp({})
// 注册一个全局自定义指令 `v-focus`
app.directive('focus', {
// 当被绑定的元素插入到 DOM 中时……
mounted(el) {
// Focus the element
el.focus()
}
})
就写在前端项目的根文件main.js里面就好,就可以注册一个自定义指令。使用也很简单,直接把v-focus写在某个dom上就行:
<div v-focus></div>
解决自适应高度的问题
经过不断的研究,下面这种写法是比较靠谱的:
app.directive('resizer', {
mounted: (el, binding) => {
const tableHeight = () => {
if (window.innerHeight >= 976) {
el.style.height = '670px'
} else {
el.style.height = `${window.innerHeight - binding.value < 200 ? 200 : (window.innerHeight - binding.value)}px`
}
}
tableHeight()
el.tableHeight = tableHeight
window.addEventListener('resize', el.tableHeight)
},
updated: (el, binding) => {
if (binding.oldValue !== binding.value) {
el.tableHeight()
}
},
beforeUnmount: el => {
window.removeEventListener('resize', el.tableHeight)
},
})
应该注意到,和vue2的自定义指令相比:
- 原本的inserted没了,很多函数也没了,取而代之的是mounted,beforeMounted,updated,beforeUpdated,beforeUnmount等,使用的时候要注意到这些。
- 另外,vue3不建议操作参数vnode,而是操作el,因为vnode包含很多额外的函数、属性,修改容易发生错误。
- binding中的新旧值就是value和oldValue,不再有什么arg
可以看出vue3的自定义指令设计简洁了很多,参数命名也规范了不少,我个人很喜欢