我们考察child组件,发现它跟一般的组件有以下两点不同:
-
多了一个events字段,里面定义了许多事件及其对应的回调方法。
-
methods方法中调用了$dispatch和$broadcast,用来触发及传播事件。
事件初始化
我们需要将事件及其回调函数注册到child实例上,这样当其他组件(无论是父组件还是子组件)传来消息的时候,程序才能知道该触发哪个事件,该执行哪个回调函数。
触发及传播事件
无论是$dispatch还是$broadcast,他们都有类似的步骤。
如果是向上冒泡事件
-
在当前组件实例触发($emit)事件,执行对应的回调函数。如果事件return true,那么代表事件可传播,执行第2步。如果事件不可传播,结束。
-
找出当前组件的父组件。没有父组件?结束。有父组件?把父组件当成当前组件,重新执行第1步。
如果是向下广播事件
-
找出当前组件的所有子组件。没有子组件?结束。有子组件?执行第2步。
-
深度遍历所有子组件,把子组件当成当前组件,触发($emit)事件,执行对应的回调函数。如果事件return true,那么代表事件可传播,重新执行第1步。如果事件不可传播,结束。
相关代码如下:
注意:Vue在广播事件的时候,是不会在发起广播事件的组件触发该事件的,只会从它的下一个子组件开始触发。这与冒泡事件稍有不同。
That's all。这样我们就实现了Vue父子组件之间的通信了。参考的Vue源码依然是1.0.26版本,实现的完整代码在这儿。
后话
虽然我们实现了父子组件通信,但是,兄弟节点A、B间怎么通信呢?一个比较粗糙的思路就是:兄弟A将消息发到兄弟A、B共同的父节点C,然后再经由C转发给兄弟B。但是这样做有一个弊端,当节点很多的时候,这种传递方式就会显得杂乱无章。那么,传统的计算机是如何解决众多兄弟节点(比如,CPU、内存、硬盘等等)之间的通信的呢?答案是总线机制。这么良好的思想,我们前端怎么能不借鉴呢?所以就有了redux和vuex这些状态管理器。