持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第9天,点击查看活动详情
前言
学习框架,仅仅会使用是不够的,想要更熟悉框架,需要对源码有一定的了解。本篇文章通过vue源码解析,实现vue的事件添加@click。
介绍
v-on,缩写@,参数event,绑定事件监听器。事件类型由参数指定。表达式可以是一个方法的名字或一个内联语句,如果没有修饰符也可以省略。 用在普通元素上时,只能监听原生 DOM 事件。
代码
<button @click='handle'>点击触发</button>
<script>
new Vue({
el: '#app',
methods: {
handle(e) {
console.log('111')
console.log(e)
}
},
})
</script>
当按钮被点击,会触发methods中的handle()打印 '111',如果handle方法接收一个参数e,那么我们可以获得点击事件的参数。
实现
在实现vue添加事件之前,先来看看原生js是如何实现事件监听的
事件监听的两种实现方法:
标签中的onxxx,比如<button οnclick="btnHandler">按钮</button>js中的addEventListener,比如document.body.addEventListener("click", () => {console.log('111')})
所以,vue中想要实现添加事件,只有两种情况:onclick、addEventListener。
上述代码中,我们先分析DOM,vue是如何知道点击按钮,要触发哪个方法,我们一步步来分析。
-
在元素节点中判断是否有@click。
在
vue中,@click永远是给元素节点加的。根据之前对模板的解析知道,元素节点对应的nodeType值为1。我们只需要在
nodeType值为1的节点中,判断是否有@click,即在元素节点中判断是否有@click。我们通过hasAttribute()方法判断补充:
HTML DOM hasAttribute()方法定义和用法 hasAttribute() 方法用于判断是否有指定的属性存在,如果存在返回 true,否则返回 false。 提示: 我们可以使用 setAttribute() 来添加一个新属性,或者修改元素中已存在的属性。 实例: // 检查按钮元素是否有 onclick属性: document.getElementsByTagName("BUTTON")[0].hasAttribute("onclick"); // true代码
index.html<div id="app"> {{message}} <h1>{{name}}</h1> <h2>{{age}}</h2> <button @click='handle'>点击触发</button> </div>vue.js第一个文本节点不做判断,第二个和第三个标签节点没有
@click,所以为false,第四个标签节点有@click,所以为true -
获取
@click中的函数在
@click后,会写需要被执行的函数,我们需要在实例中,获取到@click对应的函数在
vue.js中,需要拿到vue对象,因为@click绑定的方法在vue对象中,即为options然后根据
@click中的方法名,找到vue对象中,对应的方法代码
// 元素节点 if (item.nodeType == 1) { // 判断元素节点是否有@click if (item.hasAttribute('@click')) { console.log(this.$options.methods['handle']) } // 递归执行模板解析 this.Parser(item) }成功获取到
@click绑定的函数,但是,获取的函数名是写死的,需要通过动态获取函数名 -
动态查找
@click绑定的方法名通过
getAttribute('@click'),就能找到对应方法名实现的时候,尽量将两边空格去除
补充:
定义和用法 getAttribute() 方法通过名称获取属性的值。 提示:如果你想返回属性请使用 getAttributeNode 方法。 实例: // 获取链接的 target 属性值: document.getElementsByTagName("a")[0].getAttribute("target"); // _blank代码
// 元素节点 if (item.nodeType == 1) { // 判断元素节点是否有@click if (item.hasAttribute('@click')) { console.log(item.getAttribute('@click').trim()) } // 递归执行模板解析 this.Parser(item) } -
为有
@click的元素节点绑定点击事件上面已经分析过了,添加事件的两种形式,我们这里用到
js添加事件的方法addEventListener,添加的为click事件,方法名为动态获取的方法。代码
// 元素节点 if (item.nodeType == 1) { // 判断元素节点是否有@click if (item.hasAttribute('@click')) { // 获取@click节点绑定的事件名 let value = item.getAttribute('@click').trim() // 为存在@click的节点,添加事件 item.addEventListener('click', () => { //执行事件 this.$options.methods[value]() }) }点击按钮,
click事件成功被执行,但是事件对象e没有获取到 -
获取事件对象
e获取事件对象,只需要
vue在执行click事件时,传递event给vue对象中的方法即可这里需要注意
this指向代码
// 元素节点 if (item.nodeType == 1) { // 判断元素节点是否有@click if (item.hasAttribute('@click')) { // 获取@click节点绑定的事件名 let value = item.getAttribute('@click').trim() // 为存在@click的节点,添加事件 item.addEventListener('click', (e) => { //执行事件,修改this指向当前对象,并传递e this.$options.methods[value].bind(this)(e) }) } // 递归执行模板解析 this.Parser(item) }成功执行事件,并获取到事件对象
e
总结
vue中添加事件的原理并不难,只要从原生DOM中添加事件的方法出发,就能理清楚vue添加事件的原理。
实现思路是:vue通过模板解析从模板中找到绑定@click的元素节点,获取@click的方法名,再为此元素节点绑定一个click事件(通过addEventListener方法),并在vue对象中找到对应方法,传递事件对象,最后帮你执行。
最后,vue中还有很多事件处理方法,不过其他的事件处理的原理和@click也差不多,根据这个思路,就能实现。