钩子函数接收四个参数:el、binding、vnode 和 oldVnode。其中 binding 对象包含了指令的大部分信息。
Vue.directive('my-directive', {
bind(el, binding, vnode, oldVnode) {
// el: 指令绑定的元素
// binding: 包含指令信息的对象
// vnode: Vue 编译生成的虚拟节点
// oldVnode: 上一个虚拟节点(仅在 update 和 componentUpdated 中可用)
}
})
el 是指令绑定的 DOM 元素,可以直接操作:
Vue.directive('color', {
bind(el, binding) {
el.style.color = binding.value
el.classList.add('highlight')
el.setAttribute('data-custom', 'true')
}
})
binding 对象包含以下属性:
指令名称,不包含 v- 前缀:
Vue.directive('my-directive', {
bind(el, binding) {
console.log(binding.name) // 'my-directive'
}
})
指令的绑定值:
<div v-demo="1 + 1"></div>
<script>
Vue.directive('demo', {
bind(el, binding) {
console.log(binding.value) // 2
}
})
</script>
指令绑定的旧值,仅在 update 和 componentUpdated 中可用:
Vue.directive('demo', {
update(el, binding) {
if (binding.value !== binding.oldValue) {
console.log('值已改变')
}
}
})
字符串形式的指令表达式:
<div v-demo="1 + 1"></div>
<script>
Vue.directive('demo', {
bind(el, binding) {
console.log(binding.expression) // '1 + 1'
}
})
</script>
传给指令的参数:
<div v-demo:foo="message"></div>
<script>
Vue.directive('demo', {
bind(el, binding) {
console.log(binding.arg) // 'foo'
}
})
</script>
包含修饰符的对象:
<div v-demo.foo.bar="message"></div>
<script>
Vue.directive('demo', {
bind(el, binding) {
console.log(binding.modifiers) // { foo: true, bar: true }
}
})
</script>
<div id="app">
<div v-demo:foo.bar="message"></div>
</div>
<script>
Vue.directive('demo', {
bind(el, binding) {
console.log('name:', binding.name) // 'demo'
console.log('value:', binding.value) // 'Hello Vue!'
console.log('expression:', binding.expression) // 'message'
console.log('arg:', binding.arg) // 'foo'
console.log('modifiers:', binding.modifiers) // { bar: true }
}
})
new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
</script>
Vue 2.6+ 支持动态指令参数:
<div v-mydirective:[direction]="value"></div>
<script>
new Vue({
el: '#app',
data: {
direction: 'left',
value: '100px'
}
})
Vue.directive('mydirective', {
bind(el, binding) {
const direction = binding.arg // 'left'
const value = binding.value // '100px'
el.style[direction] = value
}
})
</script>
如果指令需要多个值,可以传入对象:
<div v-demo="{ color: 'red', size: '20px' }"></div>
<script>
Vue.directive('demo', {
bind(el, binding) {
const { color, size } = binding.value
el.style.color = color
el.style.fontSize = size
}
})
</script>
vnode 是 Vue 编译生成的虚拟节点:
Vue.directive('demo', {
bind(el, binding, vnode) {
console.log(vnode.context) // 组件上下文
console.log(vnode.elm) // 真实 DOM 元素
console.log(vnode.data) // VNode 数据
console.log(vnode.componentOptions) // 组件选项
}
})
<div id="app">
<p v-color:text="'red'">文本颜色</p>
<p v-color:bg="'blue'">背景颜色</p>
</div>
<script>
Vue.directive('color', {
bind(el, binding) {
const type = binding.arg
const color = binding.value
if (type === 'text') {
el.style.color = color
} else if (type === 'bg') {
el.style.backgroundColor = color
}
}
})
</script>
<div id="app">
<button v-permission:edit="hasPermission">编辑</button>
<button v-permission.delete="hasPermission">删除</button>
<button v-permission:admin.disable="hasPermission">管理</button>
</div>
<script>
Vue.directive('permission', {
bind(el, binding) {
const action = binding.arg
const modifiers = binding.modifiers
const hasPermission = binding.value
if (!hasPermission) {
if (modifiers.disable) {
el.disabled = true
el.style.opacity = '0.5'
} else {
el.style.display = 'none'
}
}
}
})
new Vue({
el: '#app',
data: {
hasPermission: false
}
})
</script>
<div id="app">
<input v-debounce:500="search" placeholder="搜索...">
<input v-debounce:1000.immediate="search" placeholder="立即执行">
</div>
<script>
Vue.directive('debounce', {
bind(el, binding) {
const delay = parseInt(binding.arg) || 300
const immediate = binding.modifiers.immediate
let timer = null
el._debounce = function(event) {
if (immediate && !timer) {
binding.value(event)
}
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
if (!immediate) {
binding.value(event)
}
timer = null
}, delay)
}
el.addEventListener('input', el._debounce)
},
unbind(el) {
el.removeEventListener('input', el._debounce)
delete el._debounce
}
})
new Vue({
el: '#app',
methods: {
search(event) {
console.log('搜索:', event.target.value)
}
}
})
</script>
| 属性 | 说明 | 示例 |
|---|---|---|
| name | 指令名 | 'demo' |
| value | 绑定值 | 2 |
| oldValue | 旧值 | 1 |
| expression | 表达式 | '1 + 1' |
| arg | 参数 | 'foo' |
| modifiers | 修饰符 | { bar: true } |
理解钩子参数后,接下来学习实用的指令示例。