目标:自己造出一个 v-x 指令,点击打印出 'x'
一. 声明一个全局指令
全局的意思是,这个指令在任何组件里都能使用
Vue.directive('x',{
inserted: function (el) {
el.addEventListener('click',()=>{
console.log('x')
})
}
})
比如定义在main.js里,实例引用了其他组件,那么其他组件里都可以使用 v-x 指令。
v-x 被加到哪个元素上,哪个元素就是el。 inserted 表示元素被插入到DOM中后,给el添加一个点击事件。
二. 声明一个局部指令
new Vue({
...,
directives:{
'x':{
inserted: function(el) {
el.addEventListener("click", () => {
console.log("x");
});
}
},
'y':directiveOptions
}
})
在一个实例或组件的选项里声明,使用 directives 选项,可以声明多个指令。
v-x 指令只能在该组件里使用,其他地方用不了,包括它引用的组件。
三. directiveOptions
directiveOptions 里有五个函数属性:
-
bind(el,info,vnode,oldVnode):只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。(类似created) -
inserted(参数同上):被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。(类似mounted) -
update(参数同上):所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新。 (类似updated) -
componentUpdated(参数同上):指令所在组件的 VNode 及其子 VNode 全部更新后调用。 -
unbind(参数同上):只调用一次,指令与元素解绑时调用。(类似destroyed)
前两个和最后一个比较常用。
函数的四个参数:
el:指令所绑定的元素,可以用来直接操作 DOM。info:一个对象,包含以下 property:- name:指令名,不包括 v- 前缀。
- value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2。
- oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
- expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"。
- arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"。
- modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。
vnode:Vue 编译生成的虚拟节点。oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。
自己实现v-on
new Vue({
directives: {
on2: {
// bind 可以改为 inserted
bind(el, info) {
console.log(info)
el.addEventListener(info.arg, info.value);
// Vue 自带的 v-on 并不是这样实现的,它更复杂,用了事件委托
},
unbind(el, info) {
el.removeEventListener(info.arg, info.value);
}
}
},
template: `
<button v-on2:click="hi">点我</button>
`,
methods: {
hi() {
console.log("hi");
}
}
}).$mount("#app");
声明一个局部指令,on2。当指令绑到元素上时,给元素添加一个事件监听。事件名现在还不知道,需要用户传,比如是一个click事件,可以通过 info.arg 获取。事件处理函数通过 info.value 获取。
好的习惯是给元素绑定事件监听后,要在一个时间解除绑定。于是在元素消亡时解除事件监听。
四. 指令的作用:减少重复的DOM操作
Vue 实例/组件主要用于数据绑定,事件监听,DOM更新
而原生的DOM操作就可以封装成Vue指令
如果某种DOM操作经常使用,或者比较复杂,就可以封装成指令