这篇文章的由来,其实是朋友在群里好奇@click绑定方式的种类,大家七嘴八舌讨论出来的,觉得过程还是比较有意义,就记录下来:
1、原生js绑定点击事件
好久不用原生js绑定事件,基本都已经忘了怎么绑定。还把括号给搞丢了,实际应该是在html绑定的时候需要(),在js中绑定不需要
// html 不加括号会导致函数不执行
<div onclick="test()">点我</div>
<div id="testDom"></div>
// js
functiontest() {
console.log('立即执行了')
return () => {
console.log('这里是点击踩执行')
}
}
function test2() {
console.log('立即执行了')
return () => {
console.log('这里是点击踩执行')
}
}
let dom = document.querySelector("#testDom")
console.log('dom',dom)
let child = document.createElement('div')
child.innerHTML = `<div οnclick="test2()">点我</div>`
dom.appendChild(child)
附参考链接:为什么html里面的onclick函数后面要加(),而js里面不需要?
2、vue中绑定点击事件
思考
基于上边第1点,抛出问题:为什么vue绑定函数,已下两种方式都行?
<button @click="testClick">点我</button>
<button @click="testClick(123)">点我2</button>
其实开始讨论到这个问题的时候,还没有确定给出上边原生的结论,所以先去做了下测试,确定了原生html中onclick是不支持函数名称不带括号的绑定方式的。
做完测试,开始思考会有什么方式实现。先屡一下vue的编译过程:
初步怀疑在tem=>ast=>render(fun)之间,因为觉得这种小事情,链路应该不会拉的很长。于是重点排查这两个阶段,这部分涉及vue源码部分,我的源码版本是2.6.0,同时推荐这篇博主的这两vue源码解析,对应需要排查的两个阶段:
template转ast:https://chenjianhong.blog.csdn.net/article/details/114731266
ast转render(fun):https://blog.csdn.net/weixin_42752574/article/details/114766191
有了源码分析,找到入口debug就行了,但是注意看命名,vue名称还是很清晰的,根据名称很容易就看明白函数大概意思,无关函数跳过就行了。接下来放一下调试demo:
本地调试vue源码demo: https://github.com/yummyo/vueClickDemo
<div id="app">
<button @click="testClick">点我</button>
<button @click="testClick(123)">点我2</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
},
methods: {
testClick(){
console.log(123)
}
}
})
</script>
在本地新建html,然后将以上内容拷入并运行,同时打开控制台找到source标签页,根据源码解析,找到createCompilerCreator(源码位置:vue-2.6\src\compiler\index.js)函数
如图箭头所标注,对应我们要排查的两个阶段
查看ast,此时只是将tem转为了对应的ast,事件并没有做处理,接下来查看下一阶段
查看code变量对应值
此时发现了问题,按钮对应函数,已经被包裹了一层函数(蓝色框),可以对比下前边不加括号的按钮事件(红色框)
此时,基本就有了大概的思路,前边提到,js中绑定函数不需要加括号,如:
dom.onclick = testClick
有了上边的render字符串的数据接口,我们自己也可以循环绑定对应事件。
结论
vue在ast=》render(fun)阶段,做了处理,对于不带括号的函数绑定,不做处理,对于带括号的函数绑定,实际包括了一层函数在外边。