自定义指令
基础
除了核心提供的默认指令集之外,Vue.js 还允许你注册自定义指令。自定义指令提供了一种机制,可以将数据更改映射到任意 DOM 行为。
你可以使用 Vue.directive(id, definition)
方法注册全局自定义指令,传入一个 **指令 ID** 和一个 **定义对象**。你也可以通过将自定义指令包含在组件的 directives
选项中来注册本地自定义指令。
钩子函数
定义对象可以提供几个钩子函数(都是可选的)
bind: 只调用一次,当指令第一次绑定到元素时。
update: 第一次调用时紧随
bind
之后,使用初始值,然后在绑定值发生更改时再次调用。新值和旧值作为参数提供。unbind: 只调用一次,当指令从元素上解绑时。
示例
|
注册后,你可以在 Vue.js 模板中像这样使用它(记住要添加 v-
前缀)
|
当你只需要 update
函数时,你可以传入一个单一函数而不是定义对象
|
指令实例属性
所有钩子函数都将被复制到实际的 **指令对象** 中,你可以在这些函数内部以它们的 this
上下文访问它们。指令对象公开了一些有用的属性
- el: 指令绑定的元素。
- vm: 拥有此指令的上下文 ViewModel。
- expression: 绑定的表达式,不包括参数和过滤器。
- arg: 参数(如果存在)。
- name: 指令的名称,不带前缀。
- modifiers: 包含修饰符的对象(如果有)。
- descriptor: 包含整个指令解析结果的对象。
- params: 包含参数属性的对象。 下面解释。
你应该将所有这些属性视为只读,并且永远不要修改它们。你也可以将自定义属性附加到指令对象,但要小心不要意外覆盖现有的内部属性。
一个使用其中一些属性的自定义指令示例
|
|
结果
对象字面量
如果你的指令需要多个值,你也可以传入一个 JavaScript 对象字面量。请记住,指令可以接受任何有效的 JavaScript 表达式
|
|
字面量修饰符
当指令与字面量修饰符一起使用时,它的属性值将被解释为一个普通字符串,并直接传递到 update
方法中。update
方法也将只调用一次,因为普通字符串不能是响应式的。
|
|
元素指令
在某些情况下,我们可能希望我们的指令以自定义元素的形式使用,而不是作为属性使用。这与 Angular 的“E”模式指令的概念非常相似。元素指令为完整的组件(在指南的前面部分解释过)提供了一种更轻量级的替代方案。你可以像这样注册一个自定义元素指令
|
然后,代替
|
我们可以写
|
元素指令不能接受参数或表达式,但它可以读取元素的属性以确定其行为。
与普通指令的一个主要区别是,元素指令是 **终端** 的,这意味着一旦 Vue 遇到一个元素指令,它将完全跳过该元素 - 只有元素指令本身才能操作该元素及其子元素。
高级选项
params
自定义指令可以提供一个 params
数组,Vue 编译器将自动提取指令绑定的元素上的这些属性。示例
|
|
此 API 还支持动态属性。this.params[key]
值会自动保持最新。此外,你可以在值发生更改时指定一个回调函数
|
|
请注意,与 props 类似,指令参数遵循 JavaScript 和 HTML 之间的相同驼峰式 <=> 短横线式映射。例如,对于在模板中用作 disable-effect
的参数,你需要在 JavaScript 中访问它为 disableEffect
。
deep
如果你的自定义指令预期用于一个对象,并且它需要在对象内部的嵌套属性发生更改时触发 update
,你需要在你的指令定义中传入 deep: true
。
|
|
twoWay
如果你的指令预期将数据写回 Vue 实例,你需要传入 twoWay: true
。此选项允许在指令内部使用 this.set(value)
|
acceptStatement
传入 acceptStatement:true
使你的自定义指令能够接受像 v-on
一样的内联语句
|
|
不过要谨慎使用,因为通常你希望避免在模板中出现副作用。
terminal
1.0.19+
Vue 通过递归遍历 DOM 树来编译模板。但是,当它遇到一个 **终端** 指令时,它将停止遍历该元素的子元素。终端指令接管了编译该元素及其子元素的任务。例如,v-if
和 v-for
都是终端指令。
编写一个自定义终端指令是一个高级主题,需要对 Vue 的编译管道有相当的了解,但这是可能的。你可以通过指定 terminal: true
来指定一个自定义终端指令。你可能还需要使用 Vue.FragmentFactory
进行部分编译。以下是一个自定义终端指令的示例,它编译并将其内容模板“注入”到页面上的另一个位置
|
|
如果你想编写一个自定义终端指令,建议你阅读内置终端指令(如 v-if
和 v-for
)的源代码,以更好地了解 Vue 的内部机制。
priority
你可以选择为你的指令提供一个优先级数字。如果没有指定优先级,将使用默认优先级 - 对于普通指令为 1000
,对于终端指令为 2000
。优先级较高的指令将在同一元素上的其他指令之前处理。具有相同优先级的指令将按照它们在元素属性列表中的出现顺序进行处理,尽管该顺序不能保证在不同的浏览器中保持一致。
你可以在 API 参考 中查看一些内置指令的优先级。此外,流程控制指令 v-if
和 v-for
在编译过程中始终具有最高优先级。