想必大家在使用Vue
的时候,会经常用的Vue
的一些指令。
比如v-model
、v-on
、v-bind
、v-if
、v-else-if
、v-for
、v-show
、v-slot
等。
那么,大家有没有遇到这些指令不能满足需求的时候,自己尝试自定义指令呢?
我们今天就跟大家一起学习一下,如何写一个简单的指令!
什么是指令?
指令是带有前缀v-
以表示它们是vue提供的特殊的属性。
指令的作用,可以理解是写在DOM
元素上的属性,而这个属性具有它特定的职责。
当表达式的值改变的时候,会产生一定的响应行为,而这些响应行为会作用在绑定的DOM
元素上。
什么是自定义指令?
除了核心的功能默认内置的指令v-model和v-show,Vue允许注册自定义指令。
Vue中代码复用的主要形式和抽象是组件,但是有的情况下,仍需对底层的DOM进行操作,这时候就可以使用自定义指令。
自定义指令的生命周期(钩子函数)
bind
只会在初始化时候调用一次,用于当前指令第一次绑定到元素时候调用
inserted
被绑定的元素插入到父亲节点时候调用
update
指令所在组件的Vnode数据更新的时候调用,但是有可能并不会发生改变,这个时候,可以通过使用钩子参数更新前后的值来区分不必要的模版更新
componentUpdated
指令所在组件的Vnode和其子Vnode全部更新后调用
unbind
指令和元素解绑的时候调用,一般是Dom中删除绑定指令的元素时就会调用
先看一下demo
<template>
<div class="hello">
<h1>局部测试生命周期test</h1>
<p v-my-local-hook="msg">{{ msg }}</p>
</div>
</template>
<script>
//测试生命周期test
export default {
name: 'HookDirective',
props: {
msg: String
},
directives:{
myLocalHook:{
bind(){
//首次绑定dom,相当于第一次初始化
console.log('bind 首次绑定dom,相当于第一次初始化')
},
inserted(){
//被绑定元素插入到父节点时候调用
console.log('inserted 被绑定元素插入到父节点时候调用')
},
update(){
console.log('update 数据更新的时候')
},
componentUpdated(){
console.log('componentUpdated 指令所在组件的Vnode及其子Vnode全部更新后调用')
},
unbind(){
console.log('unbind 只调用用一次,就是当指令与元素解绑时候调用')
}
}
}
}
</script>
然后我们看一下打印结果,可以更清晰看到其执行顺序,一般常用到的是bind
与update
![](https://i-blog.csdnimg.cn/blog_migrate/318e89a42708b5ef05e37a001b82053d.png)
![](https://i-blog.csdnimg.cn/blog_migrate/f5b524b257e083e68993068ec29ca89e.png)
生病周期(钩子函数)的参数
我们以自定义局部指令为例,打印内容顺序分别是el、binding、vnode
![](https://i-blog.csdnimg.cn/blog_migrate/428cd58827c3f98145e00aa7d6f7b059.png)
el
指令绑定的元素,可以用来直接操作DOMbinding
返回的是一个对象,值分别是name
指令的名称,不包括v-
value
通过指令传入的值oldValue
通过指令传入的上一次的值,仅在update
和componentUpdated
钩子中又返回值。expression
字符串类型的指令表达式。如图
v-my-local="{color:colorLocal,fontSize:fontSizeLocal}"
表达式即
color:colorLocal,fontSize:fontSizeLocal"
arg
传给指令的参数,如图v-my-local:argFoo
,其参数为argFoo
modifiers
一个包含修饰符的对象,如图v-my-local:argFoo.modifiersTest
,其对象为{modifiersTest:true}
arg与modifiers的区别在于一个是使用:
一个是使用.
vnode
Vue编译生成的虚拟节点oldVnode
Vue编译生成的上一个虚拟节点,仅在update
和componentUpdated
钩子中返回值。
多个参数传值(对象字面量字面量)
如果指令需要多个值,可以传入一个 JavaScript 对象字面量。
记住,指令函数能够接受所有合法的 JavaScript 表达式。
实例
自定义全局指令
(关键在于Vue.directive())
第一步在main.js中写入我们的全局指令
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
Vue.directive('myGlobal',{
bind(el,binding,vnode) {
//首次绑定dom,相当于第一次初始化
console.log(el,binding,vnode)
el.style.color=binding.value.color
el.style.fontSize=binding.value.fontSize+'px'
},
update(el, binding, vnode) {
//首次绑定dom,相当于第一次初始化
console.log(el,binding,vnode)
el.style.color=binding.value.color
el.style.fontSize=binding.value.fontSize+'px'
}
})
new Vue({
render: h => h(App),
}).$mount('#app')
第二步即可使用,我们以==app.vue==文件和==globalDirective.vue==文件为例
app.vue
<template>
<div id="app">
<div>
<HookDirective v-if="updateMsg" :msg="updateMsg"/>
<input v-model="updateMsg" type="text">
</div>
<div>
<localDirective :color-local="colorLocal" :font-size-local="fontSizeLocal"/>
<label for="fontColor1">文本颜色</label>
<input type="text" v-model="colorLocal" name="fontColor1">
<br>
<br>
<label for="fontSize1">文字大小</label>
<input type="number" v-model="fontSizeLocal" name="fontSize1" id="">
</div>
<div>
<globalDirective :color-global="colorGlobal" :font-size-global="fontSizeGlobal"/>
<label for="fontColor2">文本颜色</label>
<input type="text" v-model="colorGlobal" name="fontColor2">
<br>
<br>
<label for="fontSize2">文字大小</label>
<input type="number" v-model="fontSizeGlobal" name="fontSize2" id="">
<p v-my-global="{color:'red',fontSize:'22'}">我在主页面使用了全局指令,成功了耶~</p>
</div>
</div>
</template>
<script>
import HookDirective from './components/HookDirective.vue'
import localDirective from './components/localDirective.vue'
import globalDirective from './components/globalDirective.vue'
export default {
name: 'App',
components: {
HookDirective,
localDirective,
globalDirective
},
data(){
return{
updateMsg:'测试生命周期',
colorLocal:'red',
fontSizeLocal:'12',
colorGlobal:'blue',
fontSizeGlobal:'24'
}
}
}
</script>
globalDirective.vue
<template>
<div class="hello">
<h1>全局自定义指令demo</h1>
<p v-my-global="{color:colorGlobal,fontSize:fontSizeGlobal}">我是内部组件使用了全局指令,任意地方都可以用到我哦~</p>
</div>
</template>
<script>
//测试生命周期test
export default {
name: 'globalDirective',
props: {
colorGlobal:{
type:String,
default:'blue'
},
fontSizeGlobal:{
type:String,
default:'24'
}
},
data(){
return{
}
}
}
</script>
自定义局部指令
(关键字为directives)
<template>
<div class="hello">
<h1>局部自定义指令demo</h1>
<p v-my-local:argFoo.modifiersTest="{color:colorLocal,fontSize:fontSizeLocal}">我是局部指令</p>
</div>
</template>
<script>
export default {
name: 'localDirective',
props: {
colorLocal:{
type:String,
},
fontSizeLocal:{
type:String,
}
},
data(){
return{
}
},
directives:{
myLocal:{
bind(el,binding,vnode) {
//首次绑定dom,相当于第一次初始化
console.log(el,binding,vnode)
el.style.color=binding.value.color
el.style.fontSize=binding.value.fontSize+'px'
},
update(el, binding, vnode) {
//首次绑定dom,相当于第一次初始化
console.log(el,binding,vnode)
el.style.color=binding.value.color
el.style.fontSize=binding.value.fontSize+'px'
}
}
}
}
</script>
两个demo的最终效果展示图
![](https://i-blog.csdnimg.cn/blog_migrate/9a2f908f0f371d33ecf5e62b3fb876ba.png)
完整项目地址
https://github.com/yzren/vue-directive
分享到此,希望对小伙伴有所帮助~
在看支持小布一下吧❤️