深入浅析vue组件间事件传递
前端之家收集整理的这篇文章主要介绍了
深入浅析vue组件间事件传递,
前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
@H_5020@由于新工作需要用vue,所以最近接触最多的也是vue,因为之前一直在用react,所以对于vue上手还是很快的。
@H
502_0@我也尽量找一些他们两个的异同点,除了多了一些辅助用的
方法以外,最大的不同应该是对于组件间的通信,不仅有props,还有一种事件监听,也是可以通过组件间传递的。
@H_
502_0@但是,在vue2.+中,vue引入了diff算法和虚拟dom来提升效率。我们知道这些事为了处理频繁更新dom元素所提出的一种优化方案,可频繁变动更新以及事件监听的初始化之间是否会有矛盾,当组件需要变动时,有没有对
注册过的事件进行解绑? 我们来写一些简单的
代码印证一下。
@H_
502_0@我们写两个div做的按钮,一个是写的
HTML代码,一个是通过组件的形式插入,两个按钮完全一样,但我们加一个disabled的
属性在外层,并通过if-else来判断disabled从而
显示不同的按钮(当然正常场景下我们不会这么去写
代码,这里只是通过这种方式模拟一种特殊场景,我们自行考虑在我们的业务中是否存在这种场景)。
<div class="jb51code">
<pre class="brush:js;">
@H_
502_0@我们加一点样式,让他尽量好看一点,看着很简单,两个按钮,可点击时为他绑定一个点击事件,不可点击时不为他绑定。不同点是一个是直接写的
HTML代码,一个是组件。组件的
代码如下:
@H_
502_0@然后在mounted周期里加一个1秒的settimeout将disabled变为false,然后我们测试一下


@H_
502_0@当disabled还是true得时候,两个按钮点击都会弹出可点击的alert。但当disebled变为false的时候,上面用html写的不会再弹框,可下面用组件写的就还是会弹窗。

@H_
502_0@这种问题出现时是非常不好定位的,因为
代码上很显然不会去调取这个clicktest事件,而在
页面上,我们也能确定按钮已经变为不可点击的那一个了。那为什么这个事件还是会被调取呢?
@H_
502_0@这先要从diff算法说起,传统的diff tree算法的算法复杂度是O(n^3),而react在引入diff算法时,抛除了跨级移动的情况,即只比对同一级的节点异同,让算法复杂度降低到了O(n),让我们可以肆无忌惮(当然也要适可而止)的频繁刷新整个
页面。
@H_
502_0@(呵呵,没图)
@H_
502_0@diff有一条策略是拥有相同类的两个组件将会
生成相似的树形结构,拥有不同类的两个组件将会
生成不同的树形结构。所以它的比对顺序就是
@H_
502_0@1)tree diff
@H_
502_0@2)component diff
@H_
502_0@3)element diff
@H_
502_0@回到我们的
代码上,我们在进行component diff时,认为他们是相同的组件,然后进行element diff,即进行新增
删除和移动所以问题就是发生在了这里,在实例化组件的时候我们初始化了事件监听,但在替换相同组件里的dom时,vue并没有对已
添加到组件上的事件监听做
删除。
@H_
502_0@我们看一下vue的
代码,
1 ? toArray(cbs) : cbs
const args = toArray(arguments,1)
for (let i = 0,l = cbs.length; i < l; i++) {
try {
cbs[i].apply(vm,args)
} catch (e) {
handleError(e,vm,`event handler for "${event}"`)
}
}
}
return vm
}
@H_
502_0@vue是通过vdom里的_events
属性下确定是否有绑定事件的。我们看一下不可点击的按钮的_events
@H_
502_0@发现clicktest还在。这就是问题所在了。
@H_
502_0@那么我们该如何去回避这样的问题呢,还是应从diff的比对方式来
解决问题,还是看
代码。
@H_
502_0@也就是对diff来说,所谓相同的第一判定原则是key。
@H_
502_0@key也是react引入diff时
添加的一个
属性,用来判断前后vdom树上是否为统一元素(注意是同级关系上),所以我们只需要在
代码上加key,就可以避免这个问题
@H_
502_0@这样,我们在点击按钮时,就不会再出弹框了。
@H_
502_0@key的作用很广泛,当我们在遍历数组
生成dom时,
添加一个可确定的唯一id(注意不应该用数组索引),会优化我们的比对效率以及更少的操作dom。我们也会在某个div上
添加key以确保他不会因为兄弟元素的变动而被重新渲染(这类div一般会被绑定react或vue以外的事件或动作,如在这个div中
生成了一个canvas等)。
@H_
502_0@那么除了在组件上加这种不必要key值以外,还有别的
方法解决吗?
@H_
502_0@有的,这里有一种很反vue但是类react的方式,就是把回调事件通过props的方式传递,向下面着这样,
props: {
'clickTest': {
type: Function
}
},methods: {
handleClick() {
//this.$emit('clickTest')
this.clickTest && this.clickTest()
}
}
@H_
502_0@虽然vue给了我们更方便的事件传递的方式,但props里是允许我们去传递任何类型的,我的期望是在真实的dom上或者在公共组件的入口处以外的地方,都是通过props的方式来传递结果的。虽然这种方式很不vue,而且也享受不到v-on给我们带来的遍历,但是这样确实可以减少不必要的麻烦。
@H_
502_0@当然既然用了vue,更好的利用vue给我们带来的便利也很重要,所以对于这种很少会出现的麻烦,我们有一个预期,并可以
快速定位并修复问题,就可以了。
@H_
502_0@
总结
@H_
502_0@以上所述是小编给大家介绍的vue组件间事件传递。编程之家 jb51.cc 收集整理的教程希望能对你有所帮助,如果觉得编程之家不错,可
分享给好友!感谢
支持。