Regular进阶: 跨组件通信

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


背景

在组件化不断深入的大环境下,无论使用哪种 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: `<div on-click={ this.onClick() } ></div>`,

    name: 'LeafNode',

    onClick(){
        broadcast( 'check', { type: 'leafnode' } )
    }
})

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

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

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

上述中介者的引入的最大问题就是,所有相关组件都在 定义时 引入了对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: `<div on-click={ this.onClick() } ></div>`,

    name: 'LeafNode',

    onClick(){
        this.$broadcast( 'check', { type: 'leafnode' } )
    }
})

main.js (入口)

new Regular({
    template:`
        <Broadcastor emitter={emitter}>            <!-- 其中LeafNode 在Top内部 -->
            <Top />
        </Broadcastor>
    `,
    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来解决跨组件的数据通信的方式


免费领取验证码、内容安全、短信发送、直播点播体验包及云服务器等套餐

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


相关文章:
【推荐】 数据库路由中间件MyCat - 源代码篇(10)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容

  • 最近再看阮一峰的一篇博客提到了一本书《Software Architecture Patterns》(PDF),写...
    卓_然阅读 7,668评论 0 22
  • 任何一个好的东西(语言、框架等)最终还取决于用的人 语言和框架本身并不能保证用户的代码清晰、解耦等, 当然它只是尽...
    约书亚Luis阅读 760评论 0 1
  • 采购与供应商的关系,阿哥看来,就是亦敌亦友,又爱又恨。双方之间,你来我往,为了利益最大化,既互相支持配合,也互相提...
    烟花阿哥阅读 546评论 0 0
  • 坐在站牌的椅子上等公交,迟迟不来,马路两边的广告拍上全是优衣库的广告。说实话,我也不知道这些品牌代言人,这些麻豆是...
    别人家的小强强阅读 8,287评论 0 1
  • 这是续“培育别人的丈夫”(养育男孩)一课后又一深刻的反省。 讨好型人格在我身上演练了多年,早已深入骨髓里了吧。遇到...
    Crystal婉韵阅读 396评论 0 0