标准答案
- 自定义指令适合处理和真实 DOM 强相关的逻辑,例如自动聚焦、点击外部关闭、权限隐藏、懒加载、拖拽基础行为。
- 组件封装适合复用 UI 结构、状态和交互,例如 Dialog、Select、Upload、Table。
- composable 适合复用响应式状态和业务逻辑,例如分页、请求、表单提交、权限判断。
- 如果逻辑主要是操作元素本身,用指令;如果需要渲染结构和子组件,用组件;如果不依赖 DOM,只复用状态和方法,用 composable。
- 指令里要注意生命周期清理。绑定事件、Observer、定时器时,要在 unmounted 中释放。
题目解析
自定义指令是 DOM 行为复用工具,不应该承载复杂业务状态。
Vue 3 指令钩子和组件生命周期命名更接近,例如 mounted、updated、unmounted。
权限指令只能控制前端展示,不能替代路由守卫和服务端权限校验。
代码示例
点击外部关闭弹窗这类 DOM 事件边界,可以用指令封装。
TypeScript
import type { Directive } from 'vue'
type ClickOutsideElement = HTMLElement & {
__clickOutside__?: (event: MouseEvent) => void
}
export const vClickOutside: Directive<ClickOutsideElement, () => void> = {
mounted(el, binding) {
el.__clickOutside__ = (event) => {
if (!el.contains(event.target as Node)) {
binding.value()
}
}
document.addEventListener('click', el.__clickOutside__)
},
unmounted(el) {
if (el.__clickOutside__) {
document.removeEventListener('click', el.__clickOutside__)
}
}
}常见误区
- 把请求、状态管理和业务规则都写进指令,导致逻辑难测试也难复用。
- 指令绑定全局事件后不清理,组件卸载后仍然触发回调。
- 能用组件表达的结构复用,硬写成指令,导致模板语义不清楚。