一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第27天,点击查看活动详情。
前言
在上一篇的文章中,我们了解了vue高级语法中的mixin语法,本章节中将会和大家一起学习vue里面的自定义指令的内容。
前菜
在vue里面比如想要操作DOM,可以通过ref属性去定义,然后通过$refs获取到DOM元素从而实现操作DOM。
比如想要做一个输入框自动聚焦的功能,就可以在input标签中定义ref属性,然后在mounted生命周期函数中使用$refs操作input标签。
<script>
const app = Vue.createApp({
mounted(){
this.$refs.input.focus()
},
template: `
<div>
<input ref='input' />
</div>
`
});
const vm = app.mount('#root');
</script>
刷新页面之后,input标签就会自动获取焦点了。但是通过ref操作DOM元素在一些简单的需求中比较好用,但是它不能被复用,其实如果想要操作DOM,还可以通过自定义指令directive的方式去实现。
directive
全局指令
<script>
const app = Vue.createApp({
template: `
<div>
<input v-focus />
</div>
`
});
app.directive('focus', {
mounted(el){
el.focus()
}
})
const vm = app.mount('#root');
</script>
-
全局的
directive方法和定义组件一样,也是通过app定义的。 -
directive方法中的第一个参数是自定义指令的名称,在标签中可以通过v-指令名称的方式使用自定义指令。 -
directive方法中的第二个参数是一个对象,里面可以写当前指令的生命周期函数。 -
在生命周期中会接收一个
el参数,这个参数可以用来操作DOM元素。
局部指令
const directives = {
focus: {
mounted(el){
el.focus()
}
}
}
const app = Vue.createApp({
directives: directives,
template: `
<div>
<input v-focus />
</div>
`
});
-
局部的自定义指令方式和局部组件的定义方式差不多,都是在
app实例上面自定义一个对象。 -
自定义的对象里面会有一个指令名称的对象,指令名称里面也是当前自定义指令对应的生命周期函数。
-
组件实例中通过
directives引用局部自定义指令。 -
标签上还是通过
v-指令名称的方式使用自定义指令。
生命周期
自定义指令的生命周期和vue组件实例的生命周期是一样的,其中的区别就是:
- 组件实例的
beforeMount、mounted是组件挂载到vue上面的时候触发的。 - 自定义指令的
beforeMount、mounted是指令挂载到标签上面的时候触发的。 - 自定义指令的生命周期函数中会接收参数,从而操作DOM。
自定义指令的生命周期函数:
beforeMount、mounted、beforeUpdate、updated、beforeUnmout、unmounted
<script>
const app = Vue.createApp({
data(){
return {
show: true
}
},
template: `
<div v-if="show">
<input v-focus />
</div>
`
});
app.directive('focus', {
beforeMount(el){
console.log('focus beforeMount')
},
mounted(el){
console.log('focus mounted')
},
beforeUpdate(el){
console.log('focus beforeUpdate')
},
updated(el){
console.log('focus updated')
},
beforeUnmount(el){
console.log('focus beforeUnmount')
},
unmounted(el){
console.log('focus unmounted')
}
})
const vm = app.mount('#root');
</script>
通过v-if指令去判断DOM是否被销毁,然后在浏览器控制台中改变show的值,就会输出beforeUnmount和unmounted生命周期函数中的内容。
🐔大家可以试试用v-show指令,看看会执行哪些生命周期函数。
传值
上面用到的v-if指令,亦或是以前学到的v-show、v-model指令都会赋值,那我们自定义指令也想要赋值,并且在指令生命周期函数中使用该怎么做呢?
🌰 小例子:比如想要通过自定义指令给一个DOM元素距顶部的距离
<script>
const app = Vue.createApp({
template: `
<div v-pos="100" style="position: absolute;">
Hello World
</div>
`
});
app.directive('pos', {
mounted(el, binding){
el.style.top = binding.value + 'px'
}
})
const vm = app.mount('#root');
</script>
- 自定义指令的
mounted生命周期函数中额外接收了一个参数binding,这个参数里面有一个value就是自定义指令中传递过来的值。 - 通过
el参数操作DOM元素,然后拿到binding中的value值,就可以实现自定义指令传值了。
当然我们也可以把自定义指令的值改为动态的,这样也会方便修改。
const app = Vue.createApp({
data(){
return {
top: 110
}
},
template: `
<div v-pos="top" style="position: absolute;">
Hello World
</div>
`
});
当我们在浏览器控制台修改top的值时,发现DOM元素上的样式并没有修改,那这时候就可以用到自定义指令的另外一个生命周期函数updated。
app.directive('pos', {
mounted(el, binding){
el.style.top = binding.value + 'px'
},
updated(el, binding){
el.style.top = binding.value + 'px'
}
})
其实mounted和updated生命周期函数中的内容是一样的,那么就可以使用一种简写的方式。
app.directive('pos', (el, binding) => {
el.style.top = binding.value + 'px'
})
directive函数中第二个参数改为一个函数,同样接收el和binding两个参数,这样就可以同时实现mounted和updated生命周期函数了。
绑定属性
以前的内容中,我们可以通过v-bind:属性名亦或者v-on:事件名的方式绑定一些自定义的名称,那么在自定义指令里面是不是也可以绑定自定义属性呢?
<script>
const app = Vue.createApp({
template: `
<div v-pos:right="100" style="position: absolute;">
Hello World
</div>
`
});
app.directive('pos', (el, binding) => {
console.log('binding:', binding)
el.style.top = binding.value + 'px'
})
const vm = app.mount('#root');
</script>
在directive函数中打印了binding的值,会看到里面有一个arg就是我们在DOM元素中通过自定义指令绑定的属性,而value就是自定义指令后面传递的值。
那么我们就可以通过binding.arg的方式去使用自定义指令绑定的属性。
app.directive('pos', (el, binding) => {
el.style[binding.arg] = binding.value + 'px'
})
总结
本章节主要讲解了自定义指令directive,它也分为全局和局部,类似于组件的定义方式。还讲解了自定义指令传值、绑定属性的方式,希望大家多写写代码熟悉它的使用方法。大家一起加油!!💪🏻