自定义指令介绍
什么是自定义指令
Vue.directive( id, [definition] )
自定义指令介绍 directives - 对普通 DOM 元素进行底层操作
官方说法:除了核心功能默认内置的指令 (v-model 和 v-show),Vue 也允许注册自定义指令。注意,在 Vue2.0 中,代码复用和抽象的主要形式是组件。然而,有的情况下,你仍然需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令。
自定义指令的组成
注册或获取全局指令。
// 注册
Vue.directive('my-directive', {
bind: function () {},
inserted: function () {},
update: function () {},
componentUpdated: function () {},
unbind: function () {}
})
// 注册 (指令函数)
Vue.directive('my-directive', function () {
// 这里将会被 `bind` 和 `update` 调用
})
// getter,返回已注册的指令
var myDirective = Vue.directive('my-directive')
自定义指令钩子
* bind,inserted,update,componentUpdated,unbind
* 参数 el,binding,vnode,oldvnode
指令定义函数提供了几个钩子函数(可选):
bind: 只调用一次,指令第一次绑定到元素时调用。用这个钩子函数可以定义一个在绑定时执行一次的初始化动作。
inserted: 被绑定元素插入父节点时调用(父节点存在即可调用)。
update: 所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新
**componentUpdated:**指令所在组件的 VNode 及其子 VNode 全部更新后调用。
**unbind:**只调用一次, 指令与元素解绑时调用。
钩子函数的参数:(el, binding, vnode, oldVnode)
el:指令所绑定的元素,可以用来直接操作 DOM 。
binding:一个对象,包含以下属性
name:指令名,不包含v-的前缀;
value:指令的绑定值;例如:v-my-directive=“1+1”,value的值是2;
oldValue:指令绑定的前一个值,仅在update和componentUpdated钩子函数中可用,无论值是否改变都可用;
expression:绑定值的字符串形式;例如:v-my-directive=“1+1”,expression的值是’1+1’;
arg:传给指令的参数;例如:v-my-directive:foo,arg的值为 ‘foo’;
modifiers:一个包含修饰符的对象;例如:v-my-directive.a.b,modifiers的值为{‘a’:true,‘b’:true}
vnode:Vue编译的生成虚拟节点;
oldVnode:上一次的虚拟节点,仅在update和componentUpdated钩子函数中可用。
自定义指令的参数
v-demo:foo.a.b="message"
binding.name 可以获取指令的名字=demo
binding.value 可以获取指令的内容 =message指代的东西(message是变量)
binding.expression 获取内容的变量名
binding.arg 可以获取v-demo:foo ==> foo
binding.modifiers 可以获取指令的修饰符 v-demo:foo.a.b ==> {a:true,b:true}
<div id="hook-arguments-example" v-demo:foo.a.b="message"></div>
Vue.directive('demo', {
bind: function (el, binding, vnode) {
var s = JSON.stringify
el.innerHTML =
'name: ' + s(binding.name) + '<br>' +
'value: ' + s(binding.value) + '<br>' +
'expression: ' + s(binding.expression) + '<br>' +
'argument: ' + s(binding.arg) + '<br>' +
'modifiers: ' + s(binding.modifiers) + '<br>' +
'vnode keys: ' + Object.keys(vnode).join(',')
}
})
结果
自定义指令简单案例
自定义指令v-swiper
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!--引入是wiper.css样式-->
<link rel="stylesheet" href="./base/swiper.min.css">
<style>
.swipe{
height:300px;
}
</style>
</head>
<body>
<div id="box">
<div class="swiper-container swipe">
<div class="swiper-wrapper">
<!--内部数据datalist发生变化了,然后生成3个swiper-slide真实dom,插入到swiper-wrapper里面去-->
<div
class="swiper-slide"
v-for="(data,index) in datalist"
v-swiper:swipe="{current:index,length:datalist.length,swipe:'swipe'}"
>
{{data}}
</div>
</div>
<!--分页器-->
<div class="swiper-pagination"></div>
</div>
</div>
<!--引入swiper or vue插件-->
<script src="./base/swiper.min.js"></script>
<script src="./base/vue.js"></script>
<script>
//有很多的插件,其实只能实例化一次,
//swiper实例化了多次之后,其实还是可以进行轮播效果,但是我们发现分页器效果已经失效了。
//需求:封装一个指令v-swiper,实现内部帮助我们实例化轮播图的功能
//问题:因为有三个swiper-slide的真实dom生成然后插入,所以new Swiper实例化了3次===>导致了分页器不管用了
//解决? 等最后一个元素插入完成后再去实例化不就ok了吗?怎么样是代表最后一个元素插入了
//那么获取到最后一个插入的元素的下标 === 传入的datalist的数组的长度-1
//自定义指令 v-swiper
Vue.directive("swiper",{
inserted(el,binding,vnode){
// 这个地方是通过vnode.context获取到vue实例,然后就可以通过这个实例.datalist.length获取到数组的长度了
// console.log(vnode.context.datalist.length)
//代表最后一个元素插入完毕了,再进进行一次实例化操作就可以了
if(binding.value.current === binding.value.length-1){
//如果外部 {current,length,swipe:'swipe'}
//new Swiper("."+binding.value.swipe,{.....})
new Swiper("."+binding.arg,{ //默认swiper执行3次,因为插入了3个swiper-slide的真实dom
loop:true,
pagination:{
el:".swiper-pagination"
}
})
}
}
})
new Vue({
el:"#box",
data:{
datalist:[] //定义了初始化的数据
},
// updated(){
// new Swiper(".swipe",{
// loop:true,
// pagination:{
// el:".swiper-pagination"
// }
// })
// },
created(){
setTimeout(() => {
this.datalist = ["111","222","333"] //更改数据
// this.$nextTick(()=>{
// new Swiper(".swipe",{
// loop:true,
// pagination:{
// el:".swiper-pagination"
// }
// })
// })
}, 3000);
}
})
</script>
</body>
</html>