参见以下代码:
1 | function createButtons = (h, buttons) => props => { |
1 | createButtons(this.$createElement, [ |
编译后
1 | renderedButtons.forEach(function (item) { |
最后,在我们点击修改按钮的时候,控制台报错:
1 | Uncaught SyntaxError: Function statements require a function name |
在这里createButtons 中的某一项传递了onClick这个参数,那么在对应的渲染函数里面,最后传递给组件的是什么样的呢?
handleModify 很好理解,就是我们希望绑定的事件,但是在上面的listeners里面,还添加了click事件,其对应的函数为
因此,上面的方式,最后会把 onClick 封装到 attrs里面。
在 Vue 组件挂载会后,首次更新时,Vue 会把相应的属性更新到 DOM 上.
因此,最后会调用 ele.setAttribute(key, value) 来设置组件的属性。这里的key value 都应该是一个DOM String。在这里的场景下, key 是对应的 onClick 字符串,而 value 是一个函数,它被定义为了 Vue 组件上的一个方法。而 Vue 在实例化组件的时候,通过initMethods方法,把对应的 method 通过bind 的方式绑定了vm的上下文。因此,这里的 value,最后是一个Bound function。因此这里会把相应的函数转换为DOM String,具体的转换方法没有找到相应的文档,但是从转换结果来看,是调用了函数的toString方法。而bind返回的函数,它的toString方法,最后会返回一个表示native代码的字符串,也就是
1 | function () { [native code] } |
因此,最后输出到html里的就变成了以下内容:
1 | <button onclick="function () { [native code] }">测试</button> |
我们知道,在一个元素定义了onclick属性的情况下,点击的时候,会将其属性值当作js脚本来执行。因此,当我们点击按钮的时候,会执行上面的脚本
1 | function () { [native code] } |
然而这个脚本是非法的,不说函数体,定义一个函数有函数表达式和函数声明两种方式,而上面的这种方式只能作为匿名函数被调用,在这里被当成了函数声明,因此就报错了。
Vue updateAttrs
el.setAttribute(key, value)
总结:
当出现问题并且不知道导致问题发生的因素时,应先通过二分法快速定位到导致问题的代码,然后通过控制变量,减少场景的影响因子,在控制变量的时候,更需要注意双边其他因子的一致性,找到问题出现的原因,待解决问题后,再寻根溯源,找到产生问题的根本因素。
参考:
- https://html.spec.whatwg.org/multipage/webappapis.html#handler-onclick
- https://w3c.github.io/uievents/#event-type-click