自定义指令
📖 本节总结
自定义指令是对 DOM 操作的封装,提供 mounted、updated、unmounted 等生命周期钩子。
指令钩子函数
javascript
// 指令钩子
const myDirective = {
// 元素插入 DOM 前调用
created(el, binding, vnode) {
console.log('created')
},
// 元素插入 DOM 后调用
mounted(el, binding, vnode) {
console.log('mounted')
},
// 组件更新前调用
beforeUpdate(el, binding, vnode) {
console.log('beforeUpdate')
},
// 组件更新后调用
updated(el, binding, vnode) {
console.log('updated')
},
// 元素移除前调用
beforeUnmount(el, binding, vnode) {
console.log('beforeUnmount')
},
// 元素移除后调用
unmounted(el, binding, vnode) {
console.log('unmounted')
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
钩子参数
javascript
{
// 绑定的 DOM 元素
el: HTMLElement,
// 绑定信息
binding: {
// 指令绑定的值
value: 'hello',
// 之前的值
oldValue: 'world',
// 传递给指令的参数 (v-xxx:arg)
arg: 'focus',
// 修饰符 (v-xxx.mod1.mod2)
modifiers: { lazy: true },
// 指令类型
instance: Component,
// vnode 信息
vnode,
prevVnode
},
// VNode
vnode,
// 上一个 VNode
prevVnode
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
使用方式
局部指令
vue
<script setup>
const vFocus = {
mounted(el) {
el.focus()
}
}
</script>
<template>
<input v-focus>
</template>1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
全局指令
javascript
// main.js
const vFocus = {
mounted(el) {
el.focus()
}
}
app.directive('focus', vFocus)1
2
3
4
5
6
7
2
3
4
5
6
7
带参数的指令
vue
<!-- v-xxx:arg="value" -->
<template>
<input v-color:background="'#f00'">
<div v-color:text="'blue'">彩色文字</div>
</template>
<script setup>
const vColor = {
mounted(el, binding) {
const { arg, value } = binding
el.style[arg] = value
}
}
</script>1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
带修饰符的指令
vue
<!-- v-xxx.mod1.mod2="value" -->
<template>
<input v-autofocus.lazy.immediate>
</template>
<script setup>
const vAutofocus = {
mounted(el, binding) {
const { modifiers } = binding
if (modifiers.lazy) {
// 延迟聚焦
setTimeout(() => el.focus(), 1000)
} else {
el.focus()
}
}
}
</script>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
实战:实现 focus 指令
javascript
// 聚焦指令
const vFocus = {
mounted(el) {
el.focus()
}
}
// 使用
<input v-focus>1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
实战:实现 loading 指令
javascript
const vLoading = {
mounted(el, binding) {
if (binding.value) {
// 显示 loading
el.classList.add('loading')
el.setAttribute('disabled', '')
} else {
// 隐藏 loading
el.classList.remove('loading')
el.removeAttribute('disabled')
}
},
updated(el, binding) {
if (binding.value !== binding.oldValue) {
// 值变化时更新
if (binding.value) {
el.classList.add('loading')
} else {
el.classList.remove('loading')
}
}
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
实战:实现权限指令
javascript
const vPermission = {
mounted(el, binding) {
const { value } = binding
const hasPermission = checkPermission(value)
if (!hasPermission) {
// 没有权限,移除元素
el.parentNode?.removeChild(el)
}
}
}
// 使用
<button v-permission="'admin'">删除</button>1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
实战:图片懒加载
javascript
const vLazy = {
mounted(el, binding) {
const { src } = binding.value
// 创建观察者
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
// 进入视口,加载图片
el.src = src
observer.unobserve(el)
}
})
})
observer.observe(el)
// 保存 observer 用于清理
el._observer = observer
},
unmounted(el) {
el._observer?.disconnect()
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
指令的简写形式
javascript
// 如果只需要 mounted 和 updated
app.directive('focus', (el, binding) => {
// mounted 和 updated 都会执行这个函数
el.focus()
})1
2
3
4
5
2
3
4
5
组件上的指令
vue
<template>
<!-- 指令在组件上 -->
<MyComponent v-loading="true" />
</template>
<!-- 编译后 -->
h(MyComponent, {
vLoading: true
})1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
总结
| 钩子 | 调用时机 |
|---|---|
| created | 元素创建后 |
| mounted | 元素插入 DOM 后 |
| beforeUpdate | 组件更新前 |
| updated | 组件更新后 |
| beforeUnmount | 元素移除前 |
| unmounted | 元素移除后 |
| 参数 | 说明 |
| ------ | ------ |
| el | 指令绑定的元素 |
| binding.value | 绑定的值 |
| binding.arg | 指令参数 |
| binding.modifiers | 修饰符 |