组件间通信方式
# 组件间通信方式
# 父子组件
父组件通过 props 传递数据给子组件 父组件监听子组件 emit 出来的事件,接受子组件的数据
注意点一 父组件不仅仅可以传递数据给子组件,也可以传递函数给子组件,然后在子组件中调用该函数,从而修改父组件中的数据。这种方式也是可以的,而且这也是 react 中的常规操作。
注意点二 子组件 emit 事件,如果是自定义事件,那么只会传递给父组件。父组件的父组件是接受不到该事件的。但是如果是原生事件,那么就能接收到。
# 爷孙组件
注意这里的爷孙并不是特指爷爷和孙子,而是指那些组件层级大于等于 2 层的组件。
对于这种组件关系,我们仍然可以通过 props 一层层地去传递数据到最底层组件,也可以通过一层层的 emit 事件传递到最顶层组件。
但是这显然加大了工作量,而且不利于代码维护。
# 兄弟组件
通常需要考虑把兄弟组件都需要的数据提升到最近的公共父组件中,这样每个兄弟组件都只需要和父组件进行沟通即可,即通过 props 和 emit 来转化为爷孙组件/父子组件的通信方式。这样只要父组件中的数据变化了,那么两个兄弟组件都会得到更新。
还有一种场景,就是 A 组件 emit 事件到父组件中,父组件监听该事件,然后通过 ref 直接调用 B 组件中的方法。反过来也可以实现 B 组件触发 A 组件中的方法。
# 事件总线
还有一种方式则是通过公共事件总线来传递消息。const bus = new Vue();
在任意组件中可以
bus.$on('eventName', eventHandler);
bus.$emit('eventName');
2
这是一种功能非常强大的手段,可以做到整个页面中任意组件之间的通信,但是同时也是非常糟糕的一种设计。因为我们只能通过全局搜索才能找到哪些组件会触发事件,哪些组件会接受事件。
# redux or vuex
redux 和 vuex 都是全局唯一数据源。然后通过 dispatch 一个字符串来更新数据。
和事件总线一样,通过字符串来触发更新逻辑对于开发来说是非常效率低下的。
但是相对于事件总线来说要友好一些,主要是因为 dispatch 之后的逻辑非常明确,就是修改 store 中的数据。至于有哪些组件依赖了 store 中的数据则不是我们需要关心的。但是事件总线方案中,我们是需要时刻关心有哪些组件中订阅了某个事件的,至少需要保证事件不重名,否则就乱套了。
# 本库的实现方式
考虑 props 和 emit 的本质其实是把数据和方法分割开了。那么本库的实现方式正好与此相反。
我们把数据和方法集合到一起变成一个对象,我们称之为服务。然后通过 provide/inject 的技术,可以方便的在任意组件中获取这个服务。只要我们获取到这个对象,我们可以在模版中渲染这个对象的数据,我们可以直接调用这个对象的方法。
因为这个对象本身就是 reactive 的,所以只要数据变化了,所有依赖这个服务的组件都会自动更新。
由于是通过 provide/inject 来获取的服务,所以是可以跨越多个组件层级直接获取服务对象的。
因为服务对象是一个类的实例,所以数据类型是非常明确的,避免了上述字符串
丢失类型的问题。
我们还可以控制 provide 的位置,去控制服务对象的范围。因为服务是和组件关联的,当组件销毁的时候,服务也会跟着销毁,间接控制了服务的生命周期。
虽然本库功能很强大,但是不意味着在整个项目中全部使用它,实际上本库还是比较适合那些容器组件。而对于那些受控组件则还是建议使用 props/emit 技术。