0
点赞
收藏
分享

微信扫一扫

Vue2(笔记17) - Vue核心 - 自定义指令

要自定义指令,那DOM元素要自己操作了;

某种程度上说,自定义指令就是把原生操作DOM做了一次封装;

例如:自定义 v-hello 指令,要做4次DOM操作,封装后就可以复用,不必重写了;

 

自定义指令_函数式

Vue 引入一个新的配置对象:​ directives:{}​ 来放自定义指令;

需求1:定义一个 v-big 指令,和 v-text 功能类似,但会把绑定的数值放大 10倍;

<div id="root">
<h2>当前的n值是:<span v-text="n"></span></h2>
<h2>放大10倍后的n值是:<span v-big="n"></span></h2>
<button @click="n++">点我n+1</button>
</div>

new Vue({
el: '#root',
data: {
n: 1,
},
directives: {
big(element, binding) { // 定义这个新指定,定义不用加 v-
console.log(element, binding)
element.innerText = binding.value * 10
}
}
})

提示1:自定义指令在定义时,不用加 “v” ,在标签上使用指令的时候,要加上 "v" ; 

提示2:自定义指令的函数,可不能一上来就写 return ,而是使用 Vue 提供的两个参数来操作DOM;

提示3:element 顾名思义,就是当前要操作的DOM元素对象 <span>

提示4:binding 是一个存储着当前元素信息的对象,具体是哪些信息呢?指令名、指令的绑定值,指令的表达式等;

Vue2(笔记17) - Vue核心 - 自定义指令_自定义指令

图中看出:

element :就是 <span> 元素对象;

binding :就是 v-big 和 元素对象 <span>之间的绑定信息:

expression 是表达式 n ,​v-big="n"​,中的 n ;

rawName 是指令名;

value:指令绑定的值;

这两个参数是哪儿来的? 是Vue内置好给我们用的,有了这两个参数,再操作当前DOM是不是就更轻松了?

element.innerText = binding.value * 10

这段代码的意思就是,从 binding 中把指令绑定的值放大10倍,然后让 element 放到 innerText 上去,从而实现 v-big 指令的效果,并且实现了响应式;

Vue2(笔记17) - Vue核心 - 自定义指令_自定义指令_02

注意:big() 这种写成函数的形式,会在两个时间点执行:

1)指令与元素成功绑定时(一上来);

2)指令所在模拟被重新解析时;

下面会演示一种在模板被加载到页面时的情况;

自定义指令_对象式

需求2:定一个 v-fbind 指令,和 v-bind 功能类似,但可以让其所绑定的 input 元素默认获取焦点;

<div id="root">
<h2>当前的n值是:<span v-text="n"></span></h2>
<h2>放大10倍后的n值是:<span v-big="n"></span></h2>
<button @click="n++">点我n+1</button>
<hr>
<input type="text" v-fbind:value="n">
</div>

提示:绑定自定义指令的方式没有问题,插值没有问题,但是获取焦点上,会有点问题

new Vue({
el: '#root',
data: {
n: 1,
},
directives: {
big(element, binding) {
console.log(element, binding)
element.innerText = binding.value * 10
},
fbind(element,binding){
element.value = binding.value
element.focus()
}
}
})

看下效果,页面打开,在没点击按钮之前,input 并没有获得焦点;

Vue2(笔记17) - Vue核心 - 自定义指令_对象式_03

不是代码写错了,而是执行的时机错了,页面打开后,Vue在建立绑定的时候,元素还没渲染到页面上,代码就已经执行完了,等元素上到页面时,要执行的代码已经过去了,效果自然就没有了;

自定义指令调用的过程中,要经历几个步骤:

1)指令与元素成功绑定(bind):仅代表在内存中建立了关系,元素还没有被渲染到页面上;

2)指令所在元素被插入页面时(inserted)

3)指令所在的模板被重新解析(update)

了解完这几个步骤,代码就要写在正确的时间点上,Vue已经为这几个关键时间点内置了函数,我们只需在时间点函数中写相应代码就行,这3个时间点函数分别是:​bin()​​,​inserted()​​,​update()​;

代码改一下:

new Vue({
el: '#root',
data: {
n: 1,
},
directives: {
big(element, binding) {
// console.log(element, binding)
element.innerText = binding.value * 10
},
fbind: {
// 指令与元素成功绑定时
bind(element, binding) {
console.log('bind');
element.value = binding.value
},
// 指令所在元素被插入页面时
inserted(element, binding) {
console.log('inserted');
element.focus()
},
// 指令所在的模板被重新解析时
update(element, binding) {
console.log('update');
element.value = binding.value
// element.focus() 还可以让他继续获取焦点
}
}
}
})

提示:1建立绑定、2插入元素、3模板重解析,这3个时间点各自有代码,在错误的时间点上执行再正确的代码都可能没有效果;

提示:本例把这3个时间点执行时都log出来了,发现,bind 和 inserted 只会执行一次,update 可能会被执行多次;

Vue2(笔记17) - Vue核心 - 自定义指令_Vue_04

代码并不复杂,思考在什么时间点执行什么语句还需要经验积累;

注意:这种固定时间点的函数叫钩子函数,一般语言都有,函数名是固定的,传入的参数就叫钩子函数参数,共有四种:elememt,binding,vnode和oldVnode;

自定义指令总结

多个单词的指令

如果指令需要多少单词的组合,就使用 '-' 连接:

<span v-big-number="n"></span>

在配置对象中,还要用引号引起来:

directives: {
'big-number': {
bind() { },
inserted() { },
update() { }
},
'my-define-directive'() {}
}

函数式还是对象式

至于自定义指令使用函数式(简写)还是对象式(完整写法),就需要判断代码中是否要在 inserted 时间点执行某个功能了;


自定义指令函数中的this

// 定义局部自定义指令
directives: {
big(element, binding) {
console.log('big', this)
element.innerText = binding.value * 10
}
}

注意:这里的 this 是指 window 的,并不是指向 vm 或 元素对象的;


全局自定义指令

和全局过滤器的写法类似,把全局自定义指令写在  ​Vue.directive('xxx',function(){...})

// 定义全局指令
Vue.directive('fbind', {
// 指令与元素成功绑定时
bind(element, binding) {
element.value = binding.value
},
// 指令所在元素被插入页面时
inserted(element, binding) {
element.focus()
},
// 指令所在的模板被重新解析时
update(element, binding) {
element.value = binding.value
element.focus()
}
});
Vue.directive('big',(element,binding)=>{
element.innerText = binding.value
});


【自定义指令】总结

1)定义语法:局部指令

对象式(完整写法)
new Vue({
directives:{指令名:{配置对象(3个时间点函数)}}
})

函数式(简化写法)
new Vue({
directives:{指令名:回调函数}
})

2)定义语法:全局指令

对象式(完整写法)
Vue.directive('指令名',{
配置对象(3个时间点函数)
})

函数式(简化写法)
Vue.directive('指令名',回调函数)

3)配置对象中常用的3个回调:

1、bind :指令与元素成功绑定时调用 ;

2、inserted :指令所在元素被插入页面时调用;

3、update :指令所在模板结构被重新解析时调用;


备注:

1)指令定义时不加 “v-”,但使用时要加 “v-” ; 

2)指令名如果是多个单词,要使用 kebab-case 命名方式,不要用 camelCase命名;


举报

相关推荐

0 条评论