程序小屋

记录生活中的点滴,分享、学习、创新

文章内容 1623902332

Vue 3.0自定义指令的使用入门

提示:在阅读本文前,建议您先阅读 Vue 3 官方文档 自定义指令 章节的内容。

一、自定义指令

1、注册全局自定义指令

1
2
3
4
5
6
7
8
9
10
const app = Vue.createApp({})
 
// 注册一个全局自定义指令 v-focus
app.directive('focus', {
  // 当被绑定的元素挂载到 DOM 中时被调用
  mounted(el) {
    // 聚焦元素
    el.focus()
  }
})

2、使用全局自定义指令

1
2
3
<div id="app">
   <input v-focus />
</div>

3、完整的使用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<div id="app">
   <input v-focus />
</div>
<script>
   const { createApp } = Vue
    
   const app = Vue.createApp({}) // ①
   app.directive('focus', { // ② 
     // 当被绑定的元素挂载到 DOM 中时被调用
     mounted(el) {
       el.focus() // 聚焦元素
     }
   })
   app.mount('#app'// ③
</script>

当页面加载完成后,页面中的输入框元素将自动获得焦点。该示例的代码比较简单,主要包含 3 个步骤:创建 App 对象、注册全局自定义指令和应用挂载。其中创建 App 对象的细节,阿宝哥会在后续的文章中单独介绍,下面我们将重点分析其他 2 个步骤。首先我们先来分析注册全局自定义指令的过程。

二、注册全局自定义指令的过程

在以上示例中,我们使用 app 对象的 directive 方法来注册全局自定义指令:

1
2
3
4
5
6
app.directive('focus', {
  // 当被绑定的元素挂载到 DOM 中时被调用
  mounted(el) {
    el.focus() // 聚焦元素
  }
})

当然,除了注册全局自定义指令外,我们也可以注册局部指令,因为组件中也接受一个 directives 的选项:

1
2
3
4
5
6
7
directives: {
  focus: {
    mounted(el) {
      el.focus()
    }
  }
}

对于以上示例来说,我们使用的 app.directive 方法被定义在 runtime-core/src/apiCreateApp.ts 文件中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// packages/runtime-core/src/apiCreateApp.ts
export function createAppAPI<HostElement>(
  render: RootRenderFunction,
  hydrate?: RootHydrateFunction
): CreateAppFunction<HostElement> {
  return function createApp(rootComponent, rootProps = null) {
    const context = createAppContext()
    let isMounted = false
 
    const app: App = (context.app = {
      // 省略部分代码
      _context: context,
       
      // 用于注册或检索全局指令。
      directive(name: string, directive?: Directive) {
        if (__DEV__) {
          validateDirectiveName(name)
        }
        if (!directive) {
          return context.directives[name] as any
        }
        if (__DEV__ && context.directives[name]) {
          warn(`Directive "${name}" has already been registered in target app.`)
        }
        context.directives[name] = directive
        return app
      },
 
    return app
  }
}

通过观察以上代码,我们可以知道 directive 方法支持以下两个参数:

  • name:表示指令的名称;
  • directive(可选):表示指令的定义。

name 参数比较简单,所以我们重点分析 directive 参数,该参数的类型是 Directive 类型:

1
2
3
4
// packages/runtime-core/src/directives.ts
export type Directive<T = any, V = any> =
  | ObjectDirective<T, V>
  | FunctionDirective<T, V>

由上可知 Directive 类型属于联合类型,所以我们需要继续分析 ObjectDirective 和 FunctionDirective 类型。这里我们先来看一下 ObjectDirective 类型的定义:

1
2
3
4
5
6
7
8
9
10
11
// packages/runtime-core/src/directives.ts
export interface ObjectDirective<T = any, V = any> {
  created?: DirectiveHook<T, null, V>
  beforeMount?: DirectiveHook<T, null, V>
  mounted?: DirectiveHook<T, null, V>
  beforeUpdate?: DirectiveHook<T, VNode<any, T>, V>
  updated?: DirectiveHook<T, VNode<any, T>, V>
  beforeUnmount?: DirectiveHook<T, null, V>
  unmounted?: DirectiveHook<T, null, V>
 &nbs
*