Vue3 20.自定义指令
除了Vue内置的一系列指令(如v-model
或者v-show
等等)之外,Vue还允许注册自定义的指令(Custom Directives)。自定义指令主要是为了重用涉及普通元素的底层DOM访问的逻辑。
一个自定义指令由一个包含类似组件生命周期钩子的对象来定义。钩子函数会接收到指令所绑定元素作为其参数。下面是一个自定义指令的例子,当Vue将元素插入到DOM中后,该指令会将一个class添加到元素中:
<script setup> |
在<script setup>
中,任何以v
开头的驼峰式命名的变量都可以当做自定义指令使用。在上述例子中,vHighlight
可以在模板中以v-highlight
的形式使用。
在不使用<script setup>
的情况下,自定义指令需要通过directives
选项注册:
export default { |
将一个自定义指令全局注册到应用层级也是一种常见的做法:
const app = createApp({}) |
自定义指令使用时机
只有当所需功能只能通过直接的DOM操作来实现时,才应该使用自定义指令。
一个常见的例子是使元素获取焦点的v-focus
指令。
<script setup> |
该指令比autofocus
属性更有用,因为它不仅在页面加载时有效,而且在Vue动态插入元素时也有效。
指令钩子
一个指令的定义对象可以提供几种钩子函数(都是可选的):
const myDirective = { |
钩子参数
指令的钩子会传递以下几种参数:
el
:指令绑定到的元素,这可以用于直接操作DOMbinding
:一个对象,包含以下的属性:value
: 传递给指令的值,例如在v-my-directive="1+1"
中,值是2
oldValue
:之前的值,仅在beofreUpdate
和updated
中可用。无论值是否更改,它都可用arg
:传递给指令的参数(如果有的话)。例如在v-my-directive:foo
中,参数就是foo
modifiers
:一个包含修饰符的对象(如果有的话)。例如在v-my-directive.foo.bar
中,修饰符对象是{foo: true, bar: true}
instance
:使用该指令的组件实例dir
:指令的定义对象
vnode
:代表绑定元素的底层VNodeprevVnode
:代表之前的渲染中指令所绑定元素的VNode。仅在beforeUpdate
和updated
钩子中可用。
举个例子,像下面的指令:
<div v-example:foo.bar="baz"> |
binding
参数会是一个这样的对象:
{ |
和内置指令类似,自定义指令的参数也可以是动态的,举例来说:
<div v-example:[arg]="value"></div> |
这里指令的参数会基于组件的arg
数据属性响应式地更新。
注意⚠️:除了
el
之外,其他参数都是只读的,不要更改它们。
简化形式
对于自定义指令来说,一个很常见的情况是仅仅需要在mounted
和updated
上实现相同的行为,除此之外并不需要其他钩子。这种情况下可以直接使用一个函数来定义指令:
<div v-color="color"></div> |
app.directive('color', (el, binding) => { |
对象字面量
如果指令需要多个值,可以向它传递一个Javascript对象字面量。指令也可以接收任何合法的Javascript表达式。
<div v-demo="{ color: 'white', text: 'hello!' }"></div> |
app.directive('demo', (el, binding) => { |
不推荐在组件上使用
不推荐在组件上使用自定义指令。当组件具有多个根节点时可能会出现预期外的行为。
当在组件上使用自定义指令时,它会始终应用于组件的根节点,和透传attributes类似。
<MyComponent v-demo="test" /> |
<!-- MyComponent 的模板 --> |
需要注意的是组件可能含有多个根节点。当应用到一个多根组件时,指令将会被忽略且抛出一个警告。和attribute不同,指令不能通过v-bind="$attrs"
来传递给一个不同的元素。