经过上一篇文章的学习,实现了界面驱动数据更新,接下来实现一下其它相关的指令,比如事件相关的指令,v-on 这个指令的使用频率还是很高的,所以我们先来实现这个指令。
v-on 的作用是什么,是不是可以给某一个元素绑定一个事件。
紧接着了解了 v-on 的作用之后,我在 example.html 的结构代码当中添加了一个 div 用 v-on 绑定了一个点击事件,然后在 methods 当中添加了一个 myFn 的方法,然后在点击事件触发的时候调用了 myFn 方法。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue基本模板</title>
<script src="js/nue.js"></script>
</head>
<body>
<div id="app">
<input type="text" v-model="name"/>
<div v-on:click="myFn">我是div</div>
</div>
<script>
let vue = new Nue({
el: document.querySelector('#app'),
data: {
name: "BNTang"
},
methods: {
myFn() {
alert('myFn被执行了');
},
}
});
</script>
</body>
</html>
如上已经将基本的结构搭建完毕了,现在需要做的事情就是需要处理一下 v-on 这个指令。
首先来看我们自己编写的 Nue 源码,在创建 Nue 实例的时候, 调用了 new Compiler(this);,进入 Compiler,constructor 方法继续往下看, 在进入 this.buildTemplate(fragment);,遍历所有的节点,判断是否是一个元素时,调用了 this.buildElement(node);, 进入 buildElement 方法,可以看到之前就是在这里处理了 v-model 这个指令,现在我们需要在这里处理 v-on 这个指令。
我先将 name, value 打印到控制台,输出结果如下:
type text
v-model name
v-on:click myFn
可以得出如果我们编写的是 v-model,那么 name 就是 v-model,value 就是 name,如果编写的是 v-on:click,那么 name 就是 v-on:click,value 就是 myFn。
知道了这些信息之后就可以开展下一步了,我在将 name 按照 :
进行分割一次就会拿到的是 v-on 与 click,click 就是待会我们要注册的事件类型,在用解构的方式将 name, value 取出来,代码如下:
let [directiveName, directiveType] = name.split(':');
directiveName 就是 v-on,directiveType 就是 click。
然后再将之前的代码 name.split('-'); 改写为 directiveName.split('-');, 这个时候我们将解构出来的结果如下:
model
on
这个时候就可以在之前的工具类当中添加一个 on 方法, 来用处理 v-on,在添加 on 方法之前,改造一下根据指令名称, 调用不同的处理函数的代码,将之前的代码改写为如下:
CompilerUtil[directive](node, value, this.vm, directiveType);
多了一个 directiveType 参数,这个参数就是指令的类型,比如 v-on:click,那么 directiveType 就是 click,这个时候就可以在工具类当中添加一个 on 方法了,代码如下:
on: function (node, value, vm, type) {
node.addEventListener(type, (e) => {
alert('事件注册成功了');
});
}
这个时候我们在页面上点击 div 的时候,就会弹出一个提示框,说明事件注册成功了。
事件注册成功了是没问题,但是这个事件执行的内容,是自己的,并不是通过 v-on 绑定的,所以我们需要将这个事件执行的内容改为通过 v-on 绑定的,这个时候就需要用到之前的 methods 对象了,我们需要通过 methods 对象来获取到对应的方法,然后将这个方法执行。
接下来要改造一下创建 Nue 实例的时候,将 methods 保存起来,改造一下 Nue 的构造函数,以后在根据对应的方法名称,获取到对应的方法, 再执行即可,代码如下:
this.$methods = options.methods;
改造完毕之后,我们就可以在工具类当中的 on 方法当中,通过 methods 对象获取到对应的方法,然后执行即可,代码如下:
on: function (node, value, vm, type) {
node.addEventListener(type, (e) => {
vm.$methods[value](e);
});
}
这个时候我们在页面上点击 div 的时候,就会弹出一个提示框,说明事件注册成功了,并且事件执行的内容也是通过 v-on 绑定的。
在 myFn 方法中打印一下 this,发现并不是 Nue 的实例,而是 myFn 本身:
这个时候就需要将 myFn 的 this 改为 Nue 的实例,这个时候就需要用到 call 方法了,代码如下:
node.addEventListener(type, (e) => {
vm.$methods[value].call(vm, e);
});
call 方法的第一个参数是改变 this 的指向,第二个参数是传递的参数,这个时候我们在 myFn 方法中打印一下 this,发现已经是 Nue 的实例了。
到此为止,v-on 指令的实现已经完成了。