Close
升级到 Vue 3 | Vue 2 EOL

自定义指令

简介

除了核心提供的默认指令集 (v-modelv-show) 之外,Vue 还允许您注册自己的自定义指令。请注意,在 Vue 2.0 中,代码复用和抽象的主要形式是组件 - 但是,在某些情况下,您可能需要对普通元素进行一些低级 DOM 访问,而这正是自定义指令仍然有用的地方。例如,将焦点设置到输入元素,就像这样

当页面加载时,该元素将获得焦点(注意:autofocus 在移动 Safari 上不起作用)。事实上,如果您自访问此页面后没有点击任何其他内容,上面的输入框现在应该处于焦点状态。现在让我们构建一个实现此功能的指令

// Register a global custom directive called `v-focus`
Vue.directive('focus', {
// When the bound element is inserted into the DOM...
inserted: function (el) {
// Focus the element
el.focus()
}
})

如果您想在本地注册指令,组件也接受 directives 选项

directives: {
focus: {
// directive definition
inserted: function (el) {
el.focus()
}
}
}

然后在模板中,您可以在任何元素上使用新的 v-focus 属性,就像这样

<input v-focus>

钩子函数

指令定义对象可以提供多个钩子函数(所有函数都是可选的)

我们将在讨论 渲染函数 时,更详细地介绍 VNode

我们将在下一节中探讨传递给这些钩子的参数(即 elbindingvnodeoldVnode)。

指令钩子参数

指令钩子传递以下参数

除了 el 之外,您应该将这些参数视为只读,并且永远不要修改它们。如果您需要在钩子之间共享信息,建议通过元素的 dataset 进行共享。

使用某些这些属性的自定义指令示例

<div id="hook-arguments-example" v-demo:foo.a.b="message"></div>
Vue.directive('demo', {
bind: function (el, binding, vnode) {
var s = JSON.stringify
el.innerHTML =
'name: ' + s(binding.name) + '<br>' +
'value: ' + s(binding.value) + '<br>' +
'expression: ' + s(binding.expression) + '<br>' +
'argument: ' + s(binding.arg) + '<br>' +
'modifiers: ' + s(binding.modifiers) + '<br>' +
'vnode keys: ' + Object.keys(vnode).join(', ')
}
})

new Vue({
el: '#hook-arguments-example',
data: {
message: 'hello!'
}
})

动态指令参数

指令参数可以是动态的。例如,在 v-mydirective:[argument]="value" 中,argument 可以根据我们组件实例中的数据属性进行更新!这使得我们的自定义指令在整个应用程序中灵活使用。

假设您想创建一个自定义指令,允许您使用固定定位将元素固定到页面上。我们可以创建一个自定义指令,其中值以像素更新垂直定位,就像这样

<div id="baseexample">
<p>Scroll down the page</p>
<p v-pin="200">Stick me 200px from the top of the page</p>
</div>
Vue.directive('pin', {
bind: function (el, binding, vnode) {
el.style.position = 'fixed'
el.style.top = binding.value + 'px'
}
})

new Vue({
el: '#baseexample'
})

这将使元素固定在页面顶部 200 像素处。但是,如果我们遇到需要从左侧而不是顶部固定元素的情况,该怎么办?这时,动态参数非常有用,它可以根据每个组件实例进行更新

<div id="dynamicexample">
<h3>Scroll down inside this section ↓</h3>
<p v-pin:[direction]="200">I am pinned onto the page at 200px to the left.</p>
</div>
Vue.directive('pin', {
bind: function (el, binding, vnode) {
el.style.position = 'fixed'
var s = (binding.arg == 'left' ? 'left' : 'top')
el.style[s] = binding.value + 'px'
}
})

new Vue({
el: '#dynamicexample',
data: function () {
return {
direction: 'left'
}
}
})

结果

我们的自定义指令现在足够灵活,可以支持几种不同的用例。

函数简写

在许多情况下,您可能希望在 bindupdate 上具有相同的行为,但并不关心其他钩子。例如

Vue.directive('color-swatch', function (el, binding) {
el.style.backgroundColor = binding.value
})

对象字面量

如果您的指令需要多个值,您也可以传入 JavaScript 对象字面量。请记住,指令可以接受任何有效的 JavaScript 表达式。

<div v-demo="{ color: 'white', text: 'hello!' }"></div>
Vue.directive('demo', function (el, binding) {
console.log(binding.value.color) // => "white"
console.log(binding.value.text) // => "hello!"
})