通过自定义指令,实现对 Dom 元素的操作封装和复用!
1. 作用
对 Dom 元素的操作进行封装和复用
举例来说,如常见的内置指令
v-on
用于绑定 Dom 元素上的事件;v-bind
绑定 Dom 元素上的属性等。当我们希望自定义一个指令去操作Dom时,就需要用到自定义指令函数
。
2. 写法
1)函数写法
- 代码实现
// 写法1:函数
<template>
<h2 v-jokerls="n"></h2>
</template>
<script>
export default {
directives: {
// element: 真实DOM元素
// binding: 指令绑定元素的信息
jokerls(element, binding) {
// binding.value 相当于 v-jokerls="n" 中的 "n"
element.innerText = binding.value
}
}
}
</script>
-
被调用的时机
-
元素与指令
初次成功绑定时
-
指令所在的模板被
重新解析
时
-
-
注意
- 元素与指令成功绑定时,真实Dom 还未渲染到页面上,因此调用如
element.focus
的方法会不生效 - 只有在把 Dom 真正放入页面时调用
element.focus
方法才能生效,函数式写法无法满足,因此需要参考对象写法
- 元素与指令成功绑定时,真实Dom 还未渲染到页面上,因此调用如
2)对象写法
- 代码实现
<script>
export default {
directives: {
自定义指令名: {
bind(element, binding){
element.value = binding.value
},
inserted(element, binding) {
element.focus()
},
update(element, binding) {
// 注意!update中要赋最新值,不然在数据更新后,该节点的数据仍然是旧的
element.value = binding.value
}
}
}
}
</script>
-
被调用的时机
-
bind
:指令与元素成功绑定
时 -
inserted
:指令所在元素被放入页面
后(此时已有真实DOM
) -
update
:指令所在模板被重新解析
时
如上调用时机对应的
原生Dom操作
代码如下:const input = document.createElement('input') // bind 阶段 input.className = 'xxx' input.value = 'xxx' // 将元素插入页面 document.body.appendChild(input) // 元素被插入页面后 inserted input.focus()
-
3. 注意
1)不能使用驼峰写法
// 错误!
<span v-bigNumber='xxx'>
// 正确
<span v-big-number='xxx'>
new Vue({
directives: {
// 函数写法
'big-number': function(element, binding){
...
}
// 对象写法
'big-number'(element, binding) { ... }
}
})
2)指令中的钩子函数,this
指向了 window
directives: {
自定义指令名() {
console.log(this) // -> Window
}
}
3)指令默认只存在于当前实例,若要注册全局指令见下:
// 1.局部指令
new Vue({
directives: {
...
}
})
// 2.1 全局指令-对象(与全局过滤器 Vue.filter 一样)
Vue.directive('自定义指令名', {
bind() {...},
inserted() {...},
update() {...}
})
// 2.2 全局指令-函数
Vue.directive('自定义指令名', function(element, binding){
...
})
4)函数写法 & 对象写法区别
函数
:只调用了bind
和update
(因为大部分情况下,bind 和 update 中的逻辑是一样的,都需要赋值新的值,因此函数写法实则是提供了一种简写的形式)对象
:可以自定义配置bind、inserted、update
三个钩子函数,分别在不同时机触发
4. 总结
- 通过
directives
配置项,或Vue.directive
API 来注册自定义指令 - 函数写法只调用了
bind 和 update
钩子函数;而对象写法可以灵活配置bind、inserted、update
三个钩子函数