Open xingbofeng opened 6 years ago
赞,虽然我还没怎么研究 Vue ,但看面你上面的解析,我大概明白了 Vue 里数据的传递。且我理解你的 eventHub
方案应该也是 Vuex 的简化版,只是 Vuex 做的更强大、更完善些。
最近我也要进军 Vue 了,得多向你讨教了~
@xuexb 使用eventHub
的目的是为了解决特定的组件库开发过程中,组件层级较深,并且无法使用Vuex
情况下的状态通信问题。通常的组件库都是UI
组件库,往往层级较浅,仅仅依靠props down
和event up
就可以实现组件库与外部业务组件的状态通信。但此次组件库开发遇到的问题是组件层级较深的问题,所以探讨了几种通信形式。由于Vue
本身的状态绑定和数据通信就是通过Object.defineProperty
或者Proxy
代理的形式来拦截底层set
操作实现的观察者模式,就之前的EventHub
就直接使用了Vue
实例:
Vue.prototype.$DicomView.$EventHub = new Vue();
最近考虑到event
的触发顺序问题,因此自己实现了一个eventHub
,可见自己实现一个带权重的事件监听器
问题:不用
Vuex
怎么让兄弟组件便捷通信?甚至让业务组件和内部组件通信?答案:使用
eventHub
如果不使用
EventHub
,我们想让父组件的两个子组件,甚至两个孙子组件之间进行通信,怎么办?方案一:
Vue
自带的原生的emit
和on
的观察者模式此处
demo
可见官方文档方案二:自己实现一个
broadcast
和dispatch
虽然
broadcast
和dispatch
方法已经被Vue
官方所废弃,但是我们仍然可以自己实现一个broadcast
和dispatch
方法。原理是componentName
参数传递需要被通知的组件,然后在组件树中用递归的方式找到正确的组件名称,之后通过apply
调用对应组件的$emit
方法:之后,我们可以通过
Vue
的mixins
的方式把上述方法引入到组件实例中:思考如图所示的组件模型:
Dicom-View
是Dicom-Canvas
的父级组件,Dicom-Canvas
组件又包括有多个Dicom-View-Port
组件,我们在Dicom-View-Port
中触发一个事件,希望改变另一个Dicom-View-Port
组件的状态。我们在
Dicom-View-Port
组件中,触发一个点击事件,此时想父组件发送一个名为on-click-select-view-port
的事件:在二级组件
Dicom-Canvas
中,我们监听了这样的一个事件,希望向下广播,并希望Dicom-View
也接收这一事件,我们又在Dicom-Canvas
中向上传播这一事件:在
Dicom-View
组件,监听到该事件,改变了状态:甚至还有这样的情况,
Dicom-View
是我们的公共组件,我们并不想在业务组件里面都引入这样的broadcast
和dispatch
方法!并且,我们并不会把所有功能组件的内容全都暴露给业务组件来调用,个人认为,这样的方式缺乏可行性。方案三:使用闭包
mixins
利用闭包不会被垃圾回收机制回收的特征,采用闭包
minins
。参考Vue 另类状态管理终极方案:使用
eventHub
开发功能组件的问题是:如何定义功能组件供给外部组件调用的接口,常用的方式是,
Vue
中我们一般是通过props
传递状态进入功能组件,在功能组件中watch
这个状态的变化。看如图所示的情况:
我们在
业务组件1
中引入我们的公共组件Dicom-View
,我们希望在业务组件2
中去监听Dicom-View-Port
组件的一个事件。如果按照方案二的方式:由于
Dicom-View
是功能组件暴露给外部的唯一接口,因此外部调用功能组件只能通过Dicom-View
的接口来进行调用,我们的业务组件2
必须通过整个应用的状态流转来流转到业务组件1
的调用处来进行调用,在不使用Vuex
的情况下,我们怎么避免如此冗余的调用链,那么eventHub
的模式就登场了:eventHub
类似于服务定位器模式和观察者模式的结合,eventHub
为一个中心点,所有事件的监听和发送都会经过eventHub
这样一个中心点,如图所示:EventHub
作为事件的中心定位器,所有的事件都经过eventHub
来进行转发,不需要经过父子组件中的状态传递,我们可以把EventHub
放在Vue
的原型下面,这样可以在组件实例中直接运用:首先,在
webpack
的入口处,定义EventHub
和所有事件的原型EVENTS
:在我们的
Dicom-View-Port
组件中,注册事件:在实际业务组件中,在
created
钩子函数中,注册事件监听器:最好在组件销毁前,使用
$off
清除事件监听:如上,就完成了上述的如此复杂的组件间消息通信。
总结:通过
EventHub
的方式,更便捷清晰地解决了在不使用Vuex
的情况下的组件间通信和状态共享问题,更便捷地实现功能组件和业务组件的通信,使用EventHub
来进行功能组件的开发,不失为一种便捷的方法。