跳到主要内容

认识

2023年05月10日
柏拉文
越努力,越幸运

一、认识


除了 Vue 内置的一系列指令 (比如 v-modelv-show) 之外,Vue 还允许你注册自定义的指令 (Custom Directives)。自定义指令主要是为了重用涉及普通元素的底层 DOM 访问的逻辑(提供让我们去操作 DOM 的能力)

一个自定义指令由一个包含类似组件生命周期钩子的对象来定义。钩子函数会接收到指令所绑定元素作为其参数。这些钩子函数将来在不同的时期被调用执行,自定义指令跟 Vue3 底层内置的指令运行原理是一致的。

二、语法


2.1 对象式

const directive = {
created(el, binding, vnode, prevVnode) {
},
beforeMount(el, binding, vnode, prevVnode) {},
mounted(el, binding, vnode, prevVnode) {},
beforeUpdate(el, binding, vnode, prevVnode) {},
updated(el, binding, vnode, prevVnode) {},
beforeUnmount(el, binding, vnode, prevVnode) {},
unmounted(el, binding, vnode, prevVnode) {}
}

2.2 函数式

对于自定义指令来说,一个很常见的情况是仅仅需要在 mountedupdated 上实现相同的行为,除此之外并不需要其他钩子。这种情况下我们可以直接用一个函数来定义指令

const directive = (el,binding)=>{

}

三、用法


3.1 组合式组件指令

在组合式中, 任何以 v 开头的驼峰式命名的变量都可以被用作一个自定义指令。

<template>
<div id="div-app">
<input v-auto-focus />
</div>
</template>

<script setup>
const vAutoFocus = {
mounted: el => el.focus()
};
</script>

3.2 选项式组件指令

在选项式中, 自定义指令需要通过 directives 选项注册

<template>
<div id="div-app">
<input v-auto-focus />
</div>
</template>

<script>
import { defineComponent } from 'vue';

export default defineComponent({
directives: {
autoFocus: {
mounted(el) {
el.focus();
}
}
},
setup() {}
});
</script>

3.3 全局自定义指令

import { createApp } from 'vue';
import './style.css';
import App from './App.vue';

const app = createApp(App);

app.directive('vAutoFocus', {
mounted: el => {
return el.focus();
}
});

app.mount('#app');

3.4 全局插件自定义指令

import { App } from 'vue';

const vAutoFocus = {
install(app: App<Element>, _options: any) {
app.directive('autoFocus', {
mounted: el => {
return el.focus();
}
});
}
};

export default vAutoFocus;

四、指令数据


4.1 指令参数

指令传参如下:

<div v-xxx:arg="yy"></div>

指令接收如下

{
arg: 'arg',
modifiers: { },
value: /* `baz` 的值 */,
oldValue: /* 上一次更新时 `baz` 的值 */
}

4.2 指令修饰符

指令参数与修饰符如下:

<div v-xxx:arg.modifiers="yy"></div>

指令接收如下

{
arg: 'arg',
modifiers: { modifiers: true },
value: /* `baz` 的值 */,
oldValue: /* 上一次更新时 `baz` 的值 */
}

4.3 指令动态数据

<div v-example:foo.bar="baz">

<div v-example:[arg]="baz"></div> // 这里指令的参数会基于组件的 arg 数据属性响应式地更新。

binding 的参数情况:

{
arg: 'foo',
modifiers: { bar: true },
value: /* `baz` 的值 */,
oldValue: /* 上一次更新时 `baz` 的值 */
}

五、指令钩子


一个指令的定义对象可以提供几种钩子函数 (都是可选的), 指令的钩子会传递以下几种参数:

  • el: 指令绑定到的元素。这可以用于直接操作 DOM

  • binding: 一个对象,包含以下属性。

    • value: 传递给指令的值。例如在 v-my-directive="1 + 1" 中,值是 2

    • oldValue: 之前的值,仅在 beforeUpdateupdated 中可用。无论值是否更改,它都可用。

    • arg: 传递给指令的参数 (如果有的话)。例如在 v-my-directive:foo 中,参数是 "foo"

    • modifiers: 一个包含修饰符的对象 (如果有的话)。例如在 v-my-directive.foo.bar 中,修饰符对象是 { foo: true, bar: true }

    • instance: 使用该指令的组件实例。

    • dir: 指令的定义对象

  • vnode: 代表绑定元素的底层 VNode

  • prevNode: 之前的渲染中代表指令所绑定元素的 VNode。仅在 beforeUpdateupdated 钩子中可用。

注意: 除了 el 外,其他参数都是只读的,不要更改它们。若你需要在不同的钩子间共享信息,推荐通过元素的 dataset attribute 实现。

4.1 created

created 在绑定元素的 attribute 前或事件监听器应用前调用

语法

created(el, binding, vnode, prevVnode) {

}

4.2 beforeMount

beforeMount 在元素被插入到 DOM 前调用

语法

beforeMount(el, binding, vnode, prevVnode) {},

4.3 mounted

mounted 在绑定元素的父组件及他自己的所有子节点都挂载完成后调用

语法

mounted(el, binding, vnode, prevVnode) {}

4.4 beforeUpdate

beforeUpdate 绑定元素的父组件更新前调用

语法

beforeUpdate(el, binding, vnode, prevVnode) {}

4.5 updated

updated 在绑定元素的父组件及他自己的所有子节点都更新后调用

语法

updated(el, binding, vnode, prevVnode) {}

4.6 beforeUnmount

beforeUnmount 绑定元素的父组件卸载前调用

语法

beforeUnmount(el, binding, vnode, prevVnode) {},

4.7 unmounted

unmounted 绑定元素的父组件卸载后调用

语法

unmounted(el, binding, vnode, prevVnode) {}