自定义指令
有的情况下,你仍然需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令. 比如图片懒加载,权限校验,自动聚焦等等
自定义指令的格式:
v - 指令 : 参数 = 值
自定义指令的使用流程
定义指令
全局注册
// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
// 当被绑定的元素插入到 DOM 中时……
inserted: function (el) {
// 聚焦元素
el.focus() // 页面加载完成之后自动让输入框获取到焦点的小功能
}
})局部注册
export default {
directives:{
"abc": {
bind(el, binding) {
// 绑定指令时的逻辑
console.log('abc directive bound', el, binding);
}
,}
},
}指令的生命周期
钩子函数的参数
每个钩子函数接收的参数都是一样的
{
bind(el, binding, vnode) {
// el:指令绑定的元素
// binding:包含指令信息的对象
// vnode:Vue编译生成的虚拟节点
}
}binding对象属性:
value:指令的绑定值. 比如 v-abc="abc" ,value的值为abc
oldValue : 指令绑定的前一个值 ( 仅在 update 和 componentUpdated 中可用 )
arg : 传给指令的参数 . 比如 v-abc:apple , arg 为 apple
modifiers : 包含修饰符的对象 , 比如 v-abc.apple.color , modifiers 为 { apple:true,color:true}
expression : 字符串形式的指令表达式 . 比如 "1+1"
高级用法
动态指令参数
如果我们定义一个pin指令来讲元素固定在距离页面某一距离的位置,这个距离作为传入值对应了y轴距离,那么确定这个元素的位置还需要x轴的值,实际情况中我们大概率不会用具体的值,而是将元素固定在屏幕两侧,那左边还是右边这个条件就可以作为动态指令参数传入
<template>
<p v-pin:[direction]="200">固定元素位置</p>
</template>
<script>
Vue.directive('pin', {
bind: function(el, binding) {
el.style.position = 'fixed'
const s = binding.arg || 'top'
el.style[s] = binding.value + 'px'
}
})
export default {
data() {
return {
direction: 'left'
}
}
}
</script>权限控制
Vue.directive('permission', {
inserted(el, binding) {
const userRoles = ['admin', 'editor']
const requiredRole = binding.value
if (!userRoles.includes(requiredRole)) {
el.parentNode.removeChild(el)
}
}
})
// 使用:<button v-permission="'admin'">管理员按钮</button>输入限制
Vue.directive('input-limit', {
bind(el, binding) {
el.addEventListener('input', () => {
const regex = new RegExp(binding.value.pattern)
if (!regex.test(el.value)) {
el.value = el.value.replace(new RegExp(binding.value.replace, 'g'), '')
el.dispatchEvent(new Event('input'))
}
})
}
})
// 使用:<input v-input-limit="{ pattern: '[0-9]', replace: '[^0-9]' }">性能优化建议
避免在
update钩子中频繁操作DOM使用修饰符进行异化处理
及时在
unbind中移除事件监听和定时器对于复杂操作优先考虑组件方案
组合式API
const myDirective = {
mounted(el, binding) {
// 组合式API逻辑
const { value, modifiers } = binding
if (modifiers.animate) {
el.style.transition = 'all 0.3s'
}
},
updated(el, binding) {
// 响应式更新处理
}
}
// 全局注册
app.directive('my-directive', myDirective)
自定义指令
https://halo.jiangling.site/archives/directive