在某些情况下,我们需要对底层DOM
进行操作,而内置的指令不能满足需求,就需要自定义指令。一个自定义指令由一个包含类似组件的生命周期的钩子的对象来定义,钩子函数会接收到指令所绑定的元素作为参数。
常用两种方式进行自定义指令,一种是全局定义,另一种在当前组件中定义
// 局部定义
export default {
name:'test',
data(){
return {}
},
directives: {
focus: {
bind: function(el, bindings, vnode) {/* ... */},
inserted: function(el, bindings, vnode) { el.focus(); },
update: function(el, bindings, vnode) { /* ... */ },
componentUpdated: function(el, bindings, vnode) { /* ... */ },
unbind: function(el, bindings, vnode) { /* ... */ }
}
},
methos:{}
};
// 全局定义
const app = createApp({});
// 使 v-focus 在所有组件中都可用
app.directive("focus", {
bind: function(el, bindings, vnode) {/* ... */},
inserted: function(el, bindings, vnode) { el.focus(); },
update: function(el, bindings, vnode) { /* ... */ },
componentUpdated: function(el, bindings, vnode) { /* ... */ },
unbind: function(el, bindings, vnode) { /* ... */ }
});
// 全局和局部的调用方式相同
<input v-focus>
钩子函数
钩子函数就是拦截模块渲染流程的“挂钩”,在不同的节点拦截或监听事件,以完成自定义指令的操作。五种钩子拦截的事件分别是初始化、插入节点、渲染完成,监听绑定值的变化和销毁节点。
钩子参数即绑定到钩子函数上的参数
el:指令绑定到的元素。这可以用于直接操作 DOM
。
binding:一个对象,包含以下属性。
v-my-directive="1 + 1"
中,值是 2。beforeUpdate
和 updated
中生效。无论是否修改都可以访问。v-my-directive:foo
中,参数是 "foo"
。v-my-directive.foo.bar
中,修饰符对象是 { foo: true, bar: true }
。dir:指令的定义对象。
vnode:代表绑定元素的底层 VNode。
prevNode:代表之前的渲染中指令所绑定元素的 VNode
。仅在 beforeUpdate
和 updated
钩子中可用。
传递钩子参数的方式有如下几种
v-focus
bingdings
的 value
上v-html="'Content
'"
arg1
和value1
分别绑定到bingdings
的arg
和value
arg
可以实现动态指令参数m1
会被绑定到 bingdings
的modifier
上。允许多个修饰符用逗号连接绑定。例如 a.b.c
对应的是{a:true,b:true,c:true}
在很多时候,你可能想在 bind 和 update 时触发相同行为,而不关心其它的钩子。比如这样写:
Vue.directive('color-swatch', function (el, binding) {
el.style.backgroundColor = binding.value
})
如果指令需要多个值,可以传入一个 JavaScript 对象字面量。记住,指令函数能够接受所有合法的 JavaScript
表达式。
<div v-demo="{ color: 'white', text: 'hello!' }">div>
在vue当时我们使用指令一般是如下的方式
<template>
<div>
<el-button type="primary" v-norepeat.disabled="{time:3000}" @click="doUpdateItem">保存el-button>
div>
template>
但是我们想在render
函数里面写上面的指令,改怎么写呢?
首先想到的就是下面的写法,但是报错了
1.使用创建虚拟节点的函数
export default {
render(h) {
const time = 3000; // 这里是 v-norepeat.disabled 的值
return h(
'div',
[
h(
'el-button',
{
props: {
type: 'primary'
},
directives: [
{
name: 'norepeat',
value: {time }, // value 是指令绑定的值
arg: null, // arg 是指令的参数
modifiers: {
disabled: true // modifiers 是指令的修饰符
}
}
],
on: {
click: this.doUpdateItem
}
},
'保存'
)
]
);
},
methods: {
doUpdateItem() {
console.log('Button clicked!');
// 这里放置点击后的操作
}
}
};
export default {
render() {
const time = 3000; // 这里是 v-norepeat.disabled 的值
const directives= [
{
name: 'norepeat',
value: {time}, // value 是指令绑定的值
arg: null, // arg 是指令的参数
modifiers: {
disabled: true // modifiers 是指令的修饰符
}
}
]
return (<div><el-button type='primary' {...{directives}} onClick={this.doUpdateItem}>保存</el-button></div>)
},
methods: {
doUpdateItem() {
console.log('Button clicked!');
// 这里放置点击后的操作
}
}
};