博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Regular进阶: 跨组件通信
阅读量:5943 次
发布时间:2019-06-19

本文共 3199 字,大约阅读时间需要 10 分钟。

本文由作者郑海波授权网易云社区发布。

背景

在组件化不断深入的大环境下,无论使用哪种 MDV 框架都最终会遇到一个头疼的问题,就是「跨组件通信」。

下图是个简单的例子

这里包含「事件通信」和「数据通信」两个维度。

事件传递

为了将事件 click<LeafNode /> 传递到最外层组件,需要依次通过 <SubNode /><Sub /> 等可能本不关心这个事件的组件(即使例子里已经使用了proxy的简化语法)

数据传递

为了从 <Top /> 传递 title 这个 prop 到 <LeafNode /> , 需要层层跨越 <Sub /><SubNode /> 这些本不需要关心 title属性 的组件。

以上处理方式除了带来性能上的损耗之外,更麻烦的就是造成了可维护性的急速下降。

显而易见的事件通信解决方案

最直接的做法就是引入一个「中介者」,简而言之就是一个全局的「跳板」,下例就是一个事件中介者

mediator.js

const Regular = require('regularjs');const emitter = new Regular;//每个Regular组件都是一个事件发射器module.exports = {    broadcast: emiter.$emit.bind(emiter),    subscribe: emiter.$on.bind(emiter)}复制代码

Top.js

const { broadcast, subscribe } = require('./mediator')const Regular = require('regularjs');const Top = Regular.extend({    name: 'Top',    init(){        subscribe('check', ev =>{            // 通过emitter广播事件        })    }})复制代码

LeafNode.js

const { broadcast, subscribe } = require('path/to/mediator')const Regular = require('regularjs');const LeafNode = Regular.extend({    template: `
`, name: 'LeafNode', onClick(){ broadcast( 'check', { type: 'leafnode' } ) }})复制代码

mediator 作为一个全局单例直接被 LeafNodeTop 引用,通过它实现了直接通信.

更麻烦的兄弟节点之间的通信当然也可以这样来解决。

显而易见的解决方案引出的另一个显而易见的问题

上述中介者的引入的最大问题就是,所有相关组件都在 定义时 引入了对emitter全局耦合, 这个将导致组件无法在多工程间被复用。

一种合理的解决方案就是将对emitter的耦合, 延迟到实例化阶段。

在Regular之前的版本里,很多朋友会通过this.$parentthis.$outer等可控性很差的方式来实现,在v0.6有了一种更好的方式。

modifyBodyComponent 新生命周期

在 Regular 的 v0.6 引入了一个新的生命周期叫 modifyBodyComponent ,它用来劫持到组件包裹的所有内部组件的初始化周期。

我们用一个简单例子来实现下emitter的动态注入

Broadcastor.js

const Regular = require('regularjs');const Broadcastor = Regular.extend({    name: 'Broadcastor',    config( data ){        const emitter = data.emitter;        this._broadcast = emitter.$emit.bind(emitter),        this._subscribe =  emitter.$on.bind(emitter)    },    modifyBodyComponent( component, next ){        component.$broadcast = this._broadcast;        component.$subscribe = this._subscribe;        next(component) // 交给外层的包装器    }})复制代码

Top.js

// const { broadcast, subscribe } = require('./mediator')const Regular = require('regularjs');const Top = Regular.extend({    name: 'Top',    template: '略...',    init(){        this.$subscribe('check', ev =>{            // 通过emitter广播事件        })    }})复制代码

LeafNode.js

// const { broadcast, subscribe } = require('path/to/mediator')const Regular = require('regularjs');const LeafNode = Regular.extend({    template: `
`, name: 'LeafNode', onClick(){ this.$broadcast( 'check', { type: 'leafnode' } ) }})复制代码

main.js (入口)

new Regular({    template:`        
`, data: { emitter: new Regular }})复制代码

这样所有的组件声明都取消了对全局 emitter 的直接依赖,而是在入口(main.js) 动态传入了一个emitter

生命周期

需要注意的是modifyBodyComponent 会在 component本身compile之后运行, 但在init之前运行。以上面的例子为代表, 完整生命周期如下.

Broadcastor.config -> Broadcastor.compile    - Top.config -> Top.compile        - LeafNode.config -> LeafNode.compile            - Broadcastor.modifyBodyComponent(LeafNode)        - LeafNode.init        - Broadcastor.modifyBodyComponent(Top)    - Top.init- Broadcastor.init复制代码

下一篇,应该会以redux(rgl-redux)为例,介绍一种基于modifyBodyComponent来解决跨组件的数据通信的方式

更多网易技术、产品、运营经验分享请访问。

相关文章:

【推荐】

转载地址:http://pwzxx.baihongyu.com/

你可能感兴趣的文章
css控制div强制换行
查看>>
ios 底部用定位 fixed。在软件盘出来后,页面元素被顶上去一部分,fixed定位的footer也跑到了上面去。解决方法...
查看>>
HDU1257题解
查看>>
Iterator
查看>>
Spring MVC整合Velocity
查看>>
fiddler+android抓包工具配置使用
查看>>
Spring Data JPA 复杂/多条件组合分页查询
查看>>
css文本 颜色1
查看>>
博客搬家了
查看>>
JavaScript中的作用域,闭包和上下文
查看>>
Python中使用ElementTree解析xml
查看>>
Python LOGGING使用方法
查看>>
Dominating Patterns
查看>>
截取指定字符串
查看>>
metrics-server最新版本有坑,慎用
查看>>
linux虚拟文件系统浅析
查看>>
HBase数据压缩编码探索
查看>>
sprint计划会议总结
查看>>
团队项目冲刺1
查看>>
fon循环总是返回最后值问题
查看>>