Open youngwind opened 7 years ago
学习了~👍
希望楼主多出些这类文章,太受益了~
看了你的文章受益良多,老铁可不可以写篇关于javascript的eventloop的博文。或者老铁可不可以帮我解惑一下关于eventloop的问题https://segmentfault.com/q/1010000008960948?_ea=1787342
嗯嗯,看了知乎上讨论的那个,明白了不少,thx @youngwind
厉害~ 关注你的博客半年了, vue的源码系列断断续续看完了,也自己实现了一套。 非常感谢!! 以后会持续关注你的博客
vue父子组件通信是基于props属性来实现的 不是基于发布订阅吧
前言
继 #93 之后,我们来探索如何实现Vue的父子组件通信。 在问如何实现之前,我习惯性地思考为什么。 为什么Vue、React这些MVVM框架会出现组件通信这个概念?犹记得我去年初刚刚学前端的时候,学的还是jquery,那时候还没接触组件的概念,所有的DOM都写到一块,A处的DOM和B处的DOM并没有明确的边界。如果A处的DOM想修改B处的DOM,那么一定是A处的DOM触发某个js方法,然后该js方法直接修改B处的DOM。就这样,非常原始,也非常符合js这门脚本语言的风格。 然而,前端早已非“当年吴下阿蒙”。在不断吸收传统软件开发优良思想的过程中,前端已经越来越系统化,js也逐渐成为一门正规的语言。组件化的概念其实就很类似传统软件开发中的模块化(各模块之间有明确的边界),既然划分了模块,那么模块之间的通信自然就成为了要解决的问题。这就是为什么这些MVVM框架会出现组件通信这个概念。
目标
本文只解决父子组件通信,不解决兄弟组件通信。预期做到的效果如下所示。
注意:图中展示的效果总共有三层实例/组件,层层嵌套。他们之间传递“姓名”和“年龄”两个字段,又分为”向上冒泡“和”向下广播“两个方向,所以总共有2*2=4种事件。其中,在冒泡(dispatch)和广播(broadcast)的过程中,”姓名“事件的传递不会停止,而”年龄“事件在触发第一次的回调函数的时候,就会停止冒泡或广播。如果希望在首次触发回调之后继续冒泡或广播,那么须在events事件中指定
return true
。这与vue的实现保持一致。PS: 此处示例对应的代码比较长,就不在文中展示了,请直接阅读源码,或者运行项目直接debug。
思路
我们考察child组件,发现它跟一般的组件有以下两点不同:
先来看第一点。
事件初始化
我们需要将事件及其回调函数注册到child实例上,这样当其他组件(无论是父组件还是子组件)传来消息的时候,程序才能知道该触发哪个事件,该执行哪个回调函数。
初始化的结果可以参考下图。
触发及传播事件
无论是$dispatch还是$broadcast,他们都有类似的步骤。
如果是向上冒泡事件
return true
,那么代表事件可传播,执行第2步。如果事件不可传播,结束。如果是向下广播事件
return true
,那么代表事件可传播,重新执行第1步。如果事件不可传播,结束。相关代码如下:
注意:Vue在广播事件的时候,是不会在发起广播事件的组件触发该事件的,只会从它的下一个子组件开始触发。这与冒泡事件稍有不同。
That's all。这样我们就实现了Vue父子组件之间的通信了。参考的Vue源码依然是1.0.26版本,实现的完整代码在这儿。
后话
虽然我们实现了父子组件通信,但是,兄弟节点A、B间怎么通信呢?一个比较粗糙的思路就是:兄弟A将消息发到兄弟A、B共同的父节点C,然后再经由C转发给兄弟B。但是这样做有一个弊端,当节点很多的时候,这种传递方式就会显得杂乱无章。那么,传统的计算机是如何解决众多兄弟节点(比如,CPU、内存、硬盘等等)之间的通信的呢?答案是总线机制。这么良好的思想,我们前端怎么能不借鉴呢?所以就有了redux和vuex这些状态管理器。