33.Vue自定义指令(函数式)_vue自定义函数_未来@音律的博客-CSDN博客还有一种就是,我们去定义指令的时候,也不要去写v-前缀,定义指令的时候需要给指令起名字,那么这个指令的名字直接就叫big,而用的时候还是要规规矩矩的写v-big。像需求一这种问题,我们就使用函数的写法就能实现,需求二,我特意设置了一个细节问题,是函数实现不了的,我们就需要用对象的写法去实现。我们可以看到,当修改和v-big毫不相干的值name,都会引起big的调用,则充分说明了指令所在的模板被重新解析时,也会引起指令的重新调用。就靠big函数中收到的参数,它收到的参数中有两个比较常用,这里打印出来看一下。_vue自定义函数https://liufr.blog.csdn.net/article/details/129667146上一节我们讲了Vue自定义指令的函数式,并用它实现了第一个需求,这里我们接着实现第二个需求。
需求2:定义一个v-fbind指令,和v-bind功能类似,但可以让其所绑定的input元素默认获取焦点
根据我们上一节所学的,fbind直接写成函数,函数会收到,指令所在的元素,以及本次绑定的信息。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../js/vue.js"></script>
</head>
<body>
<!-- 准备好一个容器 -->
<div id="root">
<h2>{{name}}</h2>
<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>
</body>
<script>
Vue.config.productionTip = false;
new Vue({
el:'#root',
data:{
name:'zhangsan',
n:1
},
directives:{
big(element,binding){
console.log('big被调用');
element.innerText = binding.value * 10;
},
fbind(element,binding){
element.value = binding.value;
}
}
})
</script>
</html>
我们来看下运行效果:
写到这里就差一个功能了,就是一进这个页面,让它能够自动获取焦点。
按理来说,我们只要调用element.focus();即可,那我们来看看效果。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../js/vue.js"></script>
</head>
<body>
<!-- 准备好一个容器 -->
<div id="root">
<h2>{{name}}</h2>
<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>
</body>
<script>
Vue.config.productionTip = false;
new Vue({
el:'#root',
data:{
name:'zhangsan',
n:1
},
directives:{
big(element,binding){
console.log('big被调用');
element.innerText = binding.value * 10;
},
fbind(element,binding){
element.value = binding.value;
element.focus();
}
}
})
</script>
</html>
实现效果:
我们可以看到,这个页面一进来,并没有获取焦点,但是在点击n+1以后,却又获取了焦点。这是怎么回事呢?
接下来,我们不使用Vue,用一个原生的例子,来说明这个问题。
我们先实现一个点击创建input框的例子:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<title></title>
</head>
<body>
<button id="btn"> 点我创建一个输入框 </button>
<script type="text/javascript">
const btn = document.getElementById('btn');
btn.onclick = () => {
const input = document.createElement('input');
document.body.appendChild(input);
}
</script>
</body>
</html>
实现效果:
接下来我们实现,让这个input创建的时候,就获得焦点。还是使用刚刚的focus方法。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<title></title>
</head>
<body>
<button id="btn"> 点我创建一个输入框 </button>
<script type="text/javascript">
const btn = document.getElementById('btn');
btn.onclick = () => {
const input = document.createElement('input');
document.body.appendChild(input);
input.focus();
}
</script>
</body>
</html>
实现效果:
这里的focus在一开始就生效了,那为什么刚刚Vue也使用了同样的方法,却没有在一开始就获得焦点,而是要在点击了n+1以后才获得焦点呢?
这里就要注意,focus方法并不是放在哪里都可以生效的。 如果我们把focus方法放在document.body.appendChild(input);之前就不会起作用了。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<title></title>
</head>
<body>
<button id="btn"> 点我创建一个输入框 </button>
<script type="text/javascript">
const btn = document.getElementById('btn');
btn.onclick = () => {
const input = document.createElement('input');
input.focus();
document.body.appendChild(input);
}
</script>
</body>
</html>
实现效果:
这是因为,input这个元素,只有放在页面上,才能有资格让它去获取焦点。所以像input.focus()这种方法,一定要在input已经存在于页面之上才能操作。
那么再回到刚刚的问题, 这个页面一进来,并没有获取焦点,但是在点击n+1以后,却又获取了焦点。这是怎么回事呢?
代码没问题,那就是执行的时机有问题。那我们就需要分析一下fbind到底是什么时候被调用的。
我们上一节其实已经说过了。
1.指令与元素成功绑定时会被调用。
2.指令所在的模板被重新解析时
问题就出在第一条,指令与元素成功绑定时会被调用
请注意,这里说的是成功绑定,而不是成功放入页面时。Vue在干活时其实是分好几步的,像上面的例子。Vue在拿到input和fbind时,会先做一次绑定,这里绑定成功之后,仅仅代表着在内存里建立了关系,此时你的input元素并没有跑到页面上。所以此时去调用element.focus();当然是不奏效的。
那这个问题该怎么解决呢?我们怎么才能让这个input一进来就获取焦点呢?
我们就需要在Vue不仅把自定义指令与元素绑定成功了,而且也将input放入页面的时候,去调用
element.focus();,也就是说我们希望把Vue的时间点再划分的细一点。
只要我们把fbind写成一个函数,那这个功能就是无法实现的。因为一旦fbind被我们写成函数,那他就只有两个时机才会调用
1.指令与元素成功绑定时会被调用。
2.指令所在的模板被重新解析时
所以使用函数式,我们根本就拿不到Vue将元素放入页面的时间点。那这个时候就需要使用完整的对象写法才能实现。使用了对象写法,Vue就可以帮我们在特定的时间点执行特定的函数。
一共有3个特定函数:bind(); inserted(); update();
bind:当指令与元素成功绑定时调用
inserted:当指令所在元素被插入页面时调用
update:指令所在模板被重新解析时
我们可以把这些指令都做输出,看下实际的执行顺序。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../js/vue.js"></script>
</head>
<body>
<!-- 准备好一个容器 -->
<div id="root">
<h2>{{name}}</h2>
<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>
</body>
<script>
Vue.config.productionTip = false;
new Vue({
el:'#root',
data:{
name:'zhangsan',
n:1
},
directives:{
big(element,binding){
console.log('big被调用');
element.innerText = binding.value * 10;
},
fbind:{
//指令与元素成功绑定时
bind(){
console.log('bind');
},
//指令所在元素被插入页面时
inserted(){
console.log('inserted');
},
//指令所在模板被重新解析时
update(){
console.log('update');
}
}
}
})
</script>
</html>
实现效果:
写到这里,我们就将完整的对象式的代码写一下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../js/vue.js"></script>
</head>
<body>
<!-- 准备好一个容器 -->
<div id="root">
<h2>{{name}}</h2>
<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>
</body>
<script>
Vue.config.productionTip = false;
new Vue({
el:'#root',
data:{
name:'zhangsan',
n:1
},
directives:{
big(element,binding){
console.log('big被调用');
element.innerText = binding.value * 10;
},
fbind:{
//指令与元素成功绑定时
bind(element,binding){
element.value = binding.value;
},
//指令所在元素被插入页面时
inserted(element,binding){
element.focus();
},
//指令所在模板被重新解析时
update(element,binding){
element.value = binding.value;
element.focus();
}
}
}
})
</script>
</html>
实现效果: