前面讲了关于在Vue中如何来进行封装swiper组件的内容,本篇内容讲到使自定义组件,讲这块内容也是同样为了后续再次回顾封装swiper组件变化做铺垫内容,那么什么是自定义指令,在前面的内容讲过了好些常用的指令,如 v-modle、v-bind、v-show、v-if、v-for、v-else等等相关的指令来说就已经基本够用,而为什么出现自定义指令只再一些情况之下需要对DOM元素进行底层操作,那么就能够将其封装在指令当中,这样一来在使用的话就看不到对DOM元素进行底层操作,说到底自定义指令的目的就是为了对DOM元素进行底层操作;将底层操作封装到指令当中,其实是能够达到复用效果。下面来进行一个对自定义指令的学习使用:
全局自定义指令 - directive使用
通过一个简单的例子来演示:
<div id="app">
<div v-msg>
温馨提示
</div>
</div>
<script>
// 自定义指令 "v-msg"
Vue.directive("msg",{
// 指令生命周期之一 inserted
inserted(el){
console.log("绑定当前指令的标签插入父节点就会执行",el)
}
})
new Vue({
el:'#app',
})
</script>
编写自定义指令"v-msg",inserted是指令的生命周期之一,前面讲到的是组件的八个生命周期,inserted是什么呢?就是 v-msg 绑定的标签插入到DOM节点上就会执行 inserted 指令生命周期,那么上面讲到使用自定义指令其实就是就是要操作底层的DOM,那么打印 inserted(el) 中的第一个参数,可以通过效果看到可以访问到原生的DOM,自定义指令的本意其实也是为了让你能够访问原生DOM,解决在某些特性情况下你需要对底层DOM的操作;
下面来进行inserted时对绑定的内容做改变:当绑有 v-msg 指令插入父节点的时候它会出现一个边框的效果(1px solid black);
<script>
// 自定义指令 "v-msg"
Vue.directive("msg",{
// 指令生命周期之一 inserted
inserted(el){
console.log("绑定当前指令的标签插入父节点就会执行",el)
el.style.border = "1px solid black"
}
})
new Vue({
el:'#app',
})
</script>
那么在之前使用的 v-if 、v-show 等的一些指令能够通过传一个属性来控制,那么自定义指令 v-msg 想通过传值来更改效果行不行呢?测试一下:
<div id="app">
<div v-msg="red">温馨提示</div>
</div>
控制台会出现报错:
[Vue warn]: Property or method "red" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property.
"red"未在实例上定义,通过初始化属性,确保此属性在 data 选项中或对于基于类的组件是反应性的。
那么在此需要知道一个问题,使用v-if,v-show的这些传值是当成一个变量来进行使用的,那么在此的 red 是通过字符串的形式,那么就该使用一个引号;使用 inserted 的第二个参数 binding ,也即是绑定的内容,下面来看一下:
<div id="app">
<div v-msg=" 'red' ">温馨提示</div>
</div>
Vue.directive("msg",{
// 指令生命周期之一 inserted
inserted(el,binding){
console.log(binding);
console.log("binding.value:",binding.value);
...
通过打印 binding 可以看到关于组件的内容,通过binding。binding.value 能够获取到绑定的值字符串 red,这样就可以来进行操作;
<div id="app">
<div v-msg="'red'">
温馨提示
</div>
</div>
<script>
Vue.directive("msg",{
// 指令生命周期之一 inserted
inserted(el,binding){
el.style.border = "1px solid " + binding.value
}
})
new Vue({el:'#app'})
</script>
v-msg 传过去一个字符串red值,那么对应绑定v-msg的标签会有一个像素的实线红色边框;来看测试效果:
那么如果想附上一个蓝色或是绿色的边框,可以通过v-msg自定义指令然后以字符串的形式传入颜色:
<div v-msg="'blue'">温馨提示</div>
<div v-msg="'green'">温馨提示</div>
此时你又不想在 v-msg 当中把值写固定了,可以通过一个data定义一个变量:
<div id="app">
<div v-msg="mycolor">
温馨提示
</div>
</div>
<script>
Vue.directive("msg",{
// 指令生命周期之一 inserted
inserted(el,binding){
el.style.border = "1px solid " + binding.value
}
})
var vm = new Vue({
el:'#app',
data:{
mycolor:"red"
}
})
</script>
这样编写可以显示出来,但有什么问题呢?我通过控制台输入这样一个命令来更改 mycolor 是否会得到更新呢?
怎么还是红色呢?不应该是蓝色吗?inserted 是我们插入父节点的时候进行触发的,而对数据的更新并没有,此时data数据是最新的,但DOM节点的数据仍然是旧数据,那么就需要在指令中的update周期进行数据更新;下面看编写代码和测试效果:
Vue.directive("msg",{
// 指令生命周期之一 inserted
inserted(el,binding){
el.style.border = "1px solid " + binding.value
},
update(el,binding){
el.style.border = "1px solid " + binding.value
}
})
以上就是自定义的一个指令,虽然实际不会做这样一个比较无趣的指令,但通过这个例子能够对自定义指令有着一定的认识和了解;
下面进一步的观察代码会发现一个问题,指令的生命周期 inserted 和update 中的内容一样,inserted 是内容插入父节点是发生,而update是数据更新发生,刚好这个自定义指令也确实需要这么写,但是既然这两个内容都是一样的,那么可以换一种方式,将它编写成一个函数,在创建和更新的时候都会被调用执行的;下面来看一下这种方式是怎样:
Vue.directive("msg",function(el,binding){
el.style.border = "1px solid " + binding.value
})
测试效果:
局部自定义指令 - directives使用
上面是在全局当中来使用自定义指令,那么如果在封装组件的时候,仅为了组件的使用需要用局部的自定义指令,那么在组件中如何让来用局部的自定义指令呢? —— directives
1. 编写代码
Vue.component("child",{
template:`
<div>
<input type="text" v-focus />
<button>搜索</button>
</div>
`,
directives:{
// 指令名称
focus:{
inserted:function(el){
el.focus()
}
}
}
})
通过设置 directives 来进行注册局部指令,这个指令名称是focus,当input标签绑定 v-focus 时在组件插入到父节点当中时会自动获取焦点;
2. 测试效果
那么通过以上自定义指令的一个认识学习,为什么说自定义指令其实就是操作底层DOM ,还记得前面讲的swiper吗?为什么在Vue中会有初始化过早之类的一些问题,在其他像jquery使用就不需要担心这些问题,在Vue当中非常依赖DOM,需要去注意它会在什么时候创建完成,先前从mounted生命周期尝试再转到updated生命周期在回到mounted生命周期,通过设置key或者v-if指令一点一点去尝试才知道,那么指令的目的也就并非是一定要去操作DOM,而是它知道什么时候DOM刚刚创建完成,知道这个,我们再一次踏上了封装swiper组件的一个路程。