一、指令初探:什么是自定义指令?
大家好,我是老张。今天咱们开始聊 Vue 自定义指令。
说实话,我刚接触 Vue 那会儿,对自定义指令这玩意儿挺不屑的。心想:内置指令都够用了,干嘛还要自己造轮子?直到我在一个真实项目中栽了跟头——有个需求是要给所有输入框加一个自动聚焦功能,还要在失焦时做数据校验。用内置指令?根本搞不定。嗯,从那以后,我才真正开始研究自定义指令。
1.1 先回顾一下 Vue 内置指令
在聊自定义指令之前,咱们得先搞清楚 Vue 到底给了我们哪些现成的工具。说白了,内置指令就是 Vue 官方帮我们封装好的 DOM 操作能力。
| 指令 | 作用 | 我常用的场景 |
|---|---|---|
v-if |
条件渲染(销毁/重建) | 权限控制、弹窗显示 |
v-show |
条件渲染(切换 display) | 频繁切换的 UI 元素 |
v-for |
列表渲染 | 表格、卡片列表 |
v-bind |
动态绑定属性 | 绑定 class、style、props |
v-on |
事件监听 | 点击、输入、滚动 |
v-model |
双向数据绑定 | 表单控件 |
v-slot |
插槽 | 组件内容分发 |
v-pre |
跳过编译 | 显示原始 Mustache 标签 |
v-cloak |
防止闪烁 | 配合 CSS 使用 |
v-once |
只渲染一次 | 静态内容优化 |
1.2 什么是自定义指令?
自定义指令,说白了就是让你能直接操作 DOM 的一种方式。Vue 的核心是数据驱动视图,但有些时候,你确实需要直接跟 DOM 打交道——比如聚焦、拖拽、权限控制。
你想想看,Vue 的内置指令已经覆盖了 80% 的常见场景。但剩下的 20%,比如「点击外部区域关闭弹窗」、「长按触发事件」、「图片加载失败显示占位图」——这些内置指令就无能为力了。这时候,自定义指令就派上用场了。
核心概念:自定义指令本质上是一个对象,它包含一组生命周期钩子函数。这些钩子会在 DOM 元素的不同阶段被调用。你可以理解为:Vue 给了你一个「钩子」,让你在元素创建、更新、销毁时执行自己的逻辑。
1.3 自定义指令的应用场景
我在项目中总结了几类最常见的场景,分享给你:
- DOM 操作类:自动聚焦、拖拽、缩放、滚动加载
- 事件处理类:防抖、节流、点击外部、长按
- 权限控制类:按钮级权限、元素显隐
- UI 增强类:水印、复制、图片懒加载、文字溢出省略
- 第三方集成类:封装 jQuery 插件、图表初始化
举个例子,我曾经在一个后台管理系统中,需要实现「按钮级权限控制」。如果用 v-if 配合计算属性,每个按钮都要写一遍判断逻辑,代码冗余到爆炸。后来我封装了一个 v-permission 指令,一行代码搞定:
<button v-permission="'user:delete'">删除用户</button>
你看,是不是清爽多了?
1.4 什么时候不该用自定义指令?
- 复杂的 UI 交互 → 用组件
- 需要响应式数据 → 用计算属性或 watch
- 跨组件通信 → 用 provide/inject 或 Vuex
我曾经见过有人用自定义指令做表单校验,结果代码维护起来比老太太的裹脚布还长。嗯,后来全重构了。
1.5 一个简单的例子:v-focus
咱们先看一个最简单的自定义指令——自动聚焦。虽然 Vue 3 里可以用 ref 和 onMounted 实现,但用指令更优雅:
// 注册一个全局自定义指令
app.directive('focus', {
mounted(el) {
el.focus()
}
})
// 在模板中使用
<input v-focus placeholder="自动聚焦" />
就这么几行代码,所有输入框都能自动聚焦了。你想想看,如果不用指令,你得在每个组件里写 ref、onMounted、nextTick……重复劳动不说,还容易出错。
1.6 自定义指令 vs 组件:怎么选?
很多新手会纠结这个问题。我个人的判断标准很简单:
- 如果这个功能需要「包裹」子内容,或者有复杂的模板结构 → 用组件
- 如果这个功能只是对单个 DOM 元素做「增强」→ 用指令
举个例子:一个「拖拽弹窗」功能。弹窗本身有标题、内容、按钮,这是组件的事。但「拖拽」这个行为,只是对弹窗的根元素做事件监听和位置计算,用指令更合适。
好了,这一章咱们先热个身。下一章我会带你深入自定义指令的「钩子函数」和「参数传递」,到时候咱们手写一个完整的权限指令。敬请期待。