Vue中的自定义指令directives
直接上代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>江河三千里</title>
<script
type="text/javascript"
src="http://ljy0427.online/js/vue.js"
></script>
</head>
<body>
<div id="root">
<span v-rivers="name"></span>
<!-- 函数式 -->
<input type="text" v-frivers:value="nums" />
<!-- 对象式 -->
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false;
var vm = new Vue({
el: "#root",
data: {
name: "test",
nums: 5,
},
directives: {
rivers(item, res) {
item.innerHTML = res.value;
console.log(item, res);
},
frivers: {
bind(item, res) {
item.value = res.value;
// 指令与元素成功绑定时触发
console.log(item, res);
},
inserted(item, res) {
// 指令所在元素被插入页面时
item.focus()
},
updated(item, res) {
item.value = res.value;
// 指令所在的模板被重新解析时
console.log(item, res);
},
},
},
});
</script>
</html>
干货开始
可以看出来,在Vue中自定义指令的方式就是v-xxx,然后在directives中配置就可以了,并且配置的时候不用管v-,只用v-xxx中的xxx,而且这种配置有两种方式,一种是函数式,另一种是对象式。
两种定义方式的区别
首先看两种方式的接受参数都是两个,那么这两个参数到底是什么呢?可以打印出来看看
很明显的就可以看出来,第一个参数就是原生的dom结点,而第二个就是vue生成。
自定义指令就是操作真是的原生dom结点
函数式
rivers(item, res) {
item.innerHTML = res.value;
console.log(item, res);
}
看起来函数式很简单,但是也有一些缺陷,不过也是最常用的一种,而对象式就相对来说比较复杂了,但是其能完成函数式不能完成的东西。
对象式
frivers: {
bind(item, res) {
item.value = res.value;
// 指令与元素成功绑定时触发
console.log(item, res);
},
inserted(item, res) {
// 指令所在元素被插入页面时
item.focus()
},
updated(item, res) {
item.value = res.value;
// 指令所在的模板被重新解析时
console.log(item, res);
}
}
在对象式中,每个配置的名称都必须写对,其中有五个,这里只写了三个常用的,如下
- bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
- inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
- update:被绑定元素所在模板更新时调用,但是可能发生在其子 VNode 更新之前。
- componentUpdated:被绑定元素所在模板完成一次更新周期时调用。
- unbind:只调用一次,指令与元素解绑时调用。
举例
前面说到了有些功能是函数不能完成的,而对象式是可以完成的。
例子:一个input框,通过自定义组件的形式绑定值,并且希望在页面一加载的时候,该input框自动获取焦点。
rivers(item, res) {
item.innerHTML = res.value;
item.focus()
console.log(item, res);
}
就会有人说直接在函数里面加入获取焦点的时间,就如上代码就行了,其实这样是行不通的。
如果非要使用函数式完成该功能,可以添加一个定时器任务
rivers(item, res) {
item.innerHTML = res.value;
setTimeout(()=>{
item.focus()
},0)
console.log(item, res);
}
添加了这个定时任务之后,就可以了,至于想知道为什么,可以去抖音关注一个博主叫“抖抖代码”,里面有很多编程相关的知识,有很多讲解都是不错的,这里我就把他解释这个input框原因的视频下载下来了
其实还可以通过对象式来完成,就是在inserted中加入起对应的逻辑代码即可。
至于产生的原因,就是js和vue的底层原理了
this关键字
先看下面代码
directives: {
rivers(item, res) {
item.innerHTML = res.value;
console.log("rivers", this);
},
frivers: {
bind(item, res) {
console.log("frivers", this)
item.value = res.value;
// 指令与元素成功绑定时触发
console.log(item, res);
},
inserted(item, res) {
// 指令所在元素被插入页面时
item.focus()
},
updated(item, res) {
item.value = res.value;
// 指令所在的模板被重新解析时
console.log(item, res);
},
},
}
也就是输出当前的this,查看this指向
发现很奇怪,按理来说这里的this不应该是指向这个Vue实例么?但为什么指向的确是window
我的理解是,既然指令是操作真实的dom,那么this就没必要需要用vue来接管了,所以指向的还是window
全局自定义指令
在vue中的自定义指令,也可以定义全局的,方便其他的Vue实例来一起使用,定义方式也和过滤一样。
通过Vue.friver(),来添加对应的指令。