标准答案

  1. 自定义指令适合处理和真实 DOM 强相关的逻辑,例如自动聚焦、点击外部关闭、权限隐藏、懒加载、拖拽基础行为。
  2. 组件封装适合复用 UI 结构、状态和交互,例如 Dialog、Select、Upload、Table。
  3. composable 适合复用响应式状态和业务逻辑,例如分页、请求、表单提交、权限判断。
  4. 如果逻辑主要是操作元素本身,用指令;如果需要渲染结构和子组件,用组件;如果不依赖 DOM,只复用状态和方法,用 composable。
  5. 指令里要注意生命周期清理。绑定事件、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__)
    }
  }
}

常见误区

  • 把请求、状态管理和业务规则都写进指令,导致逻辑难测试也难复用。
  • 指令绑定全局事件后不清理,组件卸载后仍然触发回调。
  • 能用组件表达的结构复用,硬写成指令,导致模板语义不清楚。

作者信息