持续创作,加速成长!这是我参与「掘金日新计划 · 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
也差不多,根据这个思路,就能实现。