vue自定义指令,核心就是需要自己亲手去操作DOM
而vue中的内置指令例如v-model只不过是vue帮你动了dom上的display属性,
所以自定义指令,就是自己亲手对原生操作dom进行了一次封装
局部指令
需求一:定义一个v-big指令,让它和v-text功能类似,把绑定的值放大10倍
我们现在自定义一个big指令,展示放大10倍的num值,让v-big指令和v-text指令作用一样
<template>
<div class="myDiv">
<h2>当前的n值是
<span v-text='num'></span>
</h2>
<h2>放大10倍的值是
<span v-big='num'></span>
</h2>
<button @click="num++">点我加1</button>
</div>
</template>
<script>
export default {
name: '',
components:{},
props:{},
data(){
return {
num:10
}
},
methods:{},
}
</script>
<style lang="less" scoped>
</style>
运行之后打开控制台,发现报错了,报错的指令是big,diective就是指令的意思
下面我们就来定义这个big指令:
定义指令呢,有一个属性diectives,所有自定义指令都在里面定义
big指令定义有2种方式:
(1)函数式
(2)对象式
【函数式定义指令 】
先讲解函数式,通过函数式,将num的值放大10倍
有人说big函数只要有个返回值就行了吧?
注意:这个指令函数不是返回值,他是接收2个参数,我们先输出这2个参数
由此看出,a是一个dom元素。
有人说,那a是真实dom还是虚拟dom呢?
答:是真实dom。
验证:我们通过 instanceof 来判断 a 是否是html上的实例
结果是true
有人问b是啥?
答:b里面有个value,value就是v-big后面的双引号的内容,这里面是个n,因此他的value就是num的值10,还有一个expression是表达式
那如果v-big是个函数,那么value就是一个函数
那么我们现在既可以拿到真实的dom元素,又可以通过.value拿到绑定的值,那么我们就可以写放大10倍的指令了。 将参数名换成官方定义的即可。
可以看到页面出来了
那问题来了。如果我们点击按钮让n的值加1,那么红框和蓝框的值都变吗,还是只有红框值变?
答:都变
篮框的变化取决于,big函数还会不会被调用了,从验证结果来看,是会调用的
那么big指令函数何时会被调用呢?
(1)指令与元素成功绑定时(一上来)
(2)指令所在的模板被重新解析时(并不是指令所用到的数据发生更新就被调用)
需求二:定义一个v-sbind指令,和v-bind功能类似,可以让其绑定的input元素默认获取焦点
首先我们给页面添加一个input框,里面设置绑定value值为num,v-bind简介形式为冒号:
效果:
我们想要用v-sbind实现相同的效果,首先先定义v-sbind指令
注意:
focus():得到焦点时使用,blur():失去焦点时使用
按理来说这就写完了,可是效果并没有实现。看下图并没有获取焦点
这是什么原因呢?
其实是focus执行时机的问题,上面说了指令与元素成功绑定时就会调用指令函数,成功绑定只是在内存中建立了这种绑定关系,并没有放入页面,而一上来input框就已经调用了指令函数,因此对input进行焦点的获取是不起作用的。
所以对于这种情况,我们必须精确到元素放入页面的时间点,而指令的函数式写法是不符合该需求的,这样就用到了指令的对象式写法。
【对象式写法】
里面包含三种固定的函数,分别代表不同时期的触发
sbind:{
// 指令与元素成功绑定时(一上来)
bind(){
},
// 指令所在元素被插入页面时
inserted(){
},
// 指令所在的模板被重新解析时
update(){
}
}
看下触发顺序
这三个事件同样有element和binding两个参数
因此完整写法就是:
sbind: {
// 指令与元素成功绑定时(一上来)
bind(element, bidding) {
// 虽然没放入页面但是不影响赋值
element.value = bidding.value
},
// 指令所在元素被插入页面时
inserted(element, bidding) {
// 此时我们就可以在元素插入页面时再调用获取焦点事件
element.focus()
},
// 指令所在的模板被重新解析时
update(element, bidding) {
// 页面重新解析时,同样需要再次赋值,这样可以保证num的值随之变化
element.value = bidding.value
}
}
从上面代码可以看出,bind事件和update其实是一样的,而指令的函数式就是包含的这两个方法,只不过没有inserted方法,因此遇到特殊情况就用对象式,其他情况函数式就可以满足需求~
全局指令+总结
(1)命名方式
多个单词命名用 – 分隔,例如:v-big-number
定义指令的时候用单引号包裹:’v-big-number'(){ }
(2)指令回调函数中的this指向
所有指令相关的this,不是vm是window
(3)以上我们所讲解的指令都是局部指令,只能在本vue实例中使用
假如我们相把v-sbind变为全局指令:
直接在main.js中,通过vue调用directive,将sbind对象复制进来就是全局的了,所有页面都可以使用。
Vue.directive('sbind', {
// 指令与元素成功绑定时(一上来)
bind(element, bidding) {
// 虽然没放入页面但是不影响赋值
element.value = bidding.value
},
// 指令所在元素被插入页面时
inserted(element, bidding) {
// 此时我们就可以在元素插入页面时再调用获取焦点事件
element.focus()
},
// 指令所在的模板被重新解析时
update(element, bidding) {
// 页面重新解析时,同样需要再次赋值,这样可以保证num的值随之变化
element.value = bidding.value
}
})
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/149689.html