第 15 章:指令
学习目标
- 自定义指令封装 DOM 行为
- 理解钩子参数与生命周期
- 写
v-permission/v-copy等常用指令 - 避坑:全局注册与命名
一、内置指令速查
| 指令 | 作用 |
|---|---|
v-text | 文本插值 |
v-html | 原始 HTML |
v-show | 切换 display |
v-if / v-else | 条件渲染 |
v-for | 列表 |
v-on / @ | 事件 |
v-bind / : | 绑定 |
v-model | 双向 |
v-slot / # | 插槽 |
v-pre / v-cloak / v-once | 优化 |
二、自定义指令用法
ts
// src/directives/permission.ts
import type { Directive } from 'vue'
export const permission: Directive<HTMLElement, string> = {
mounted(el, binding) {
const allow = checkPermission(binding.value)
if (!allow) el.parentNode?.removeChild(el)
},
}vue
<button v-permission="'user:delete'">删除</button>⚠️ 坑 1:
v-permission移除元素后,Vue 不知道节点被删了,反而会留下空引用,所以通常推荐禁用(disabled = true)。
三、指令生命周期
ts
directive = {
created(el, binding, vnode) {}, // 元素创建
beforeMount(el, binding) {},
mounted(el, binding) {},
beforeUpdate(el, binding) {},
updated(el, binding) {},
beforeUnmount(el, binding) {},
unmounted(el, binding) {},
}参数说明:
el:DOM 元素binding:{ value, oldValue, arg, modifiers, dir, instance }
四、实战:v-copy
ts
export const copy: Directive<HTMLElement, string> = {
mounted(el, binding) {
el.addEventListener('click', async () => {
await navigator.clipboard.writeText(binding.value)
el.classList.add('copied')
setTimeout(() => el.classList.remove('copied'), 1000)
})
},
}vue
<button v-copy="text">复制</button>五、实战:v-debounce
ts
export const debounce: Directive<HTMLElement, (...args: any[]) => void> = {
mounted(el, binding) {
let timer: number | undefined
el.addEventListener('click', (e) => {
if (timer) clearTimeout(timer)
timer = window.setTimeout(() => binding.value(e), binding.arg ? +binding.arg : 300)
})
},
}vue
<button v-debounce:500="submit">提交</button>六、全局注册
ts
// src/main.ts
import { permission } from '@/directives/permission'
import { copy } from '@/directives/copy'
app.directive('permission', permission)
app.directive('copy', copy)⚠️ 坑 2:全局指令名字会自动加
v-前缀,不要写成v-permission。
七、局部注册
vue
<script setup lang="ts">
const vFocus = {
mounted: (el: HTMLElement) => el.focus(),
}
</script>
<template>
<input v-focus />
</template>八、修饰符与参数
ts
binding.arg // '500'
binding.modifiers // { stop: true }
binding.value // 表达式值vue
<div v-tooltip:foo.stop="'提示'"></div>九、本章小结
| 钩子 | 用途 |
|---|---|
mounted | DOM 已挂载,绑定事件 |
updated | 数据更新后改 DOM |
unmounted | 清理工作 |
binding.value | 指令表达式值 |
app.directive() | 全局注册 |
动手练习
- v-lazy:用 IntersectionObserver 实现图片懒加载
- v-truncate:超长文本截断,加省略号
- v-tooltip:鼠标悬浮显示自定义提示
下一章:第 16 章:动画 →