Vue 3 自定义指令怎么写?什么时候用指令,什么时候用组件?
下面是一段教学用的模拟面试。
🧑💻 面试官:Vue 自定义指令适合做什么?
🙋♂️ 我:可以封装对 DOM 的操作,比如自动聚焦。
🧑💻 面试官:带图标、错误提示和输入框的整块表单,也做成指令吗?
🙋♂️ 我:这种有结构和状态的部分,更适合组件。
🧑💻 面试官:如果指令绑定了事件监听,卸载时谁负责清理?指令放在多根节点组件上又会怎样?
指令负责复用「已有元素上的行为」,组件负责组织「一块界面」。先分清这两种职责,再讨论钩子。
面试速答(60 秒版)
Vue 自定义指令适合复用需要直接操作 DOM 的行为,比如聚焦、测量或对已有元素添加某种交互。
如果功能包含自己的界面结构、状态和子组件,通常应该做成组件,而不是用指令拼出一整块 UI。只想复用响应式逻辑,则可以考虑组合式函数。
指令通过 mounted、updated、unmounted 等钩子处理元素生命周期。需要长期保留的监听器、观察器或计时器,应当在卸载时清理。
实际使用时,我会尽量把指令放在明确的原生元素上。应用到组件时,它可能作用于组件根元素;多根节点组件没有唯一目标,不能假设指令能自动选择正确节点。也不能在服务端渲染阶段直接访问浏览器 DOM。

图:元素行为、界面、逻辑,分别复用。
知识点详解:指令、组件和组合式函数各负责什么?
从“自动聚焦”看指令的工作范围
假设弹窗打开后,需要让用户名输入框自动获得焦点。输入框本身由模板创建,指令只需要在元素挂载完成后调用 focus。
这就是适合指令的情况:它不负责创建输入框,也不负责决定表单长什么样,只为一个已经存在的元素增加行为。
TypeScript
import type { Directive } from "vue";
export const vFocus: Directive<HTMLInputElement, boolean> = {
mounted(el, binding) {
if (binding.value !== false) el.focus();
},
updated(el, binding) {
if (binding.value && !binding.oldValue) el.focus();
},
};
示例只在值从假变真时重新聚焦,避免每次更新都抢走用户的输入焦点。它使用 Vue 浏览器指令 API,Python 没有同一套官方实现。
钩子不是随便换名字的事件回调
mounted 表示元素已经挂载,可以进行依赖真实元素的操作;updated 用来响应更新,需要结合 binding 的新旧值判断是否真的要重复执行。
unmounted 则是释放资源的重要位置。假设指令创建 ResizeObserver,卸载时就应 disconnect;如果注册事件监听,则需要保留对应的处理函数,才能正确 removeEventListener。
不能在 mounted 中创建一个匿名函数,卸载时再创建另一个匿名函数,认为它们“长得一样”就能移除。监听器的函数身份必须一致。
完整钩子和 binding 内容可以核对 Vue 自定义指令文档。

图:谁绑定资源,谁安排清理。
什么时候应该换成组件或组合式函数?
| 要复用的内容 | 更适合 |
|---|---|
| 给已有输入框聚焦 | 自定义指令 |
| 输入框、标签、错误提示组成的界面 | 组件 |
| 表单校验状态、请求状态等逻辑 | 组合式函数 |
有些需求可以配合使用。比如组件负责表单结构,组合式函数负责校验,指令只处理特殊 DOM 行为。不要为了“复用”把三种职责全部塞进同一个指令。
为什么不推荐随意把指令放在组件上?
组件不是一个确定的 DOM 元素。单根组件通常可以把指令应用到根节点,但这会让调用方依赖组件内部的根节点选择。
如果组件改成多根节点,或者根节点换了,指令目标可能就不再满足原来假设。为了稳定的行为,可以让组件通过 prop 或显式方法控制聚焦,或者直接将指令绑定到内部对应元素。
此外,SSR 环境没有普通浏览器 DOM。只能在客户端有效钩子中执行 DOM 操作;需要服务端输出属性时,应按 Vue 提供的服务端指令机制处理。
面试官继续追问
权限按钮可以只用指令隐藏吗?
可以作为界面呈现手段,但不能当成权限校验。用户可以绕过页面直接请求接口,后端仍要验证权限。
每次 updated 都重新绑定监听器,可以吗?
如果不清理旧监听,会叠加处理和泄漏。应该只在需要时更新,或者先移除旧资源再创建新资源。
指令适合异步获取数据吗?
不是完全不能,但数据状态和请求生命周期通常更适合组件或组合式函数。除非异步操作明确服务于某个元素行为,否则容易让职责混乱。
面试速记卡
- 指令:复用已有 DOM 元素上的行为。
- 组件:组织界面结构与状态。
- 组合式函数:复用响应式业务逻辑。
- 生命周期:创建的监听、观察器和定时器需要清理。
- 组件与 SSR:不要假设始终有唯一可操作的浏览器元素。
公司面试真题
这道题暂未收录可核验的公司真题来源。你可以先阅读本文解析,或浏览已收录的公司面试真题。
浏览公司面试真题 →