前言
在上一篇
的文章中,我们了解了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
,它也分为全局和局部,类似于组件的定义方式。还讲解了自定义指令传值、绑定属性的方式,希望大家多写写代码熟悉它的使用方法。大家一起加油!!💪🏻