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

背景

在组件化不断深入的大环境下,无论使用哪种 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来解决跨组件的数据通信的方式

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

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

相关文章:
【推荐】 测试周期内测试进度报告规范
【推荐】 如何实现360度的手游安全防护?网易云易盾专家分享最新实践

Regular进阶: 跨组件通信的更多相关文章

  1. redux搭配react-redux进行跨组件通信开发

    Redux API 作用 createStore 用于创建一个store对象 bindActionCreators 用于简化操作,不用开发者手动触发dispatch React-redux API 作 ...

  2. vue跨组件通信的几种方法

    http://www.tuicool.com/articles/jyM32mA 在开发组件的时候,一定会遇到组件的通信,比如点击一个图标出现弹窗和蒙层,这三个分别是不同的组件.管理他们之间的状态就成了 ...

  3. Regular进阶: 几点性能优化的建议

    本文由作者郑海波授权网易云社区发布. 本文旨在用 20% 的精力解决使用Regular过程中 80% 的性能问题. 这里大部分是关于脏检查的性能优化,不了解的可以先看下<Regular脏检查介绍 ...

  4. vue组件之间的传值——中央事件总线与跨组件之间的通信($attrs、$listeners)

    vue组件之间的通信有很多种方式,最常用到的就是父子组件之间的传值,但是当项目工程比较大的时候,就会出现兄弟组件之间的传值,跨级组件之间的传值.不可否认,这些都可以类似父子组件一级一级的转换传递,但是 ...

  5. Vue组件跨层级通信

    正常组件间通信 父->子组件 是通过属性传递 子->父组件 是通过this.$emit()传递 this.$emit()返回的是this,如果需要一些值 可使用callback方式传递 p ...

  6. vue任意关系组件通信与跨组件监听状态 vue-communication

    大家好!我是木瓜太香! 众所周知,组件式开发方式给我们带来了方便,不过也引入了新的问题,组件之间的数据就像被一道无形的墙隔开,如果我们希望临时让两个组件直接通信,vuex 太巨,而 $emit 又不好 ...

  7. react第六单元(react组件通信-父子组件通信-子父组件通信-跨级组件的传参方式-context方式的传参)

    第六单元(react组件通信-父子组件通信-子父组件通信-跨级组件的传参方式-context方式的传参) #课程目标 1.梳理react组件之间的关系 2.掌握父子传值的方法 3.掌握子父传值的方法 ...

  8. Android随笔之——跨进程通信(一) Activity篇

    在Android应用开发中,我们会碰到跨进程通信的情况,例如:你用QQ通讯录打电话的时候会调用系统的拨号应用.某些新闻客户端可以将新闻分享到QQ.微信等应用,这些都是跨进程通信的情况.简而言之,就是一 ...

  9. vue组件详解(三)——组件通信

    组件之间通信可以用下图表示: 组件关系可分为父子组件通信.兄弟组件通信.跨级组件通信. 一.自定义事件 当子组件需要向父组件传递数据时,就要用到自定义事件. 子组件用$emit ()来触发事件,父组件 ...

随机推荐

  1. SpringMVC工作原理1(基础机制)

    图1.基本原理图 Spring工作流程描述       1. 用户向服务器发送请求,请求被Spring 前端控制Servelt DispatcherServlet捕获:       2. Dispat ...

  2. ContentProvider-------------自定义的内容提供者 然后去访问

    自定义提供者 import android.content.Context; import android.database.DatabaseErrorHandler; import android. ...

  3. WebMagic写的网络爬虫

    一.前言 最近因为有爬一些招聘网站的招聘信息的需要,而我之前也只是知道有“网络爬虫”这个神奇的名词,具体是什么.用什么实现.什么原理.如何实现比较好都不清楚,因此最近大致研究了一下,当然,研究的并不是 ...

  4. nginx 反向代理 502 Bad Gateway

    查看nginx的error.log日志文件发现如下信息: upstream sent too big header while reading response header from upstrea ...

  5. php在线支付流程

    1.企业与银行的两种接入方式: (1).企业直接与银行对接. 优点:直接与银行进行财务结算,资金安全,适合资金流较大企业.         缺点:开发和维护工作量较大,分别与每家银行签订合同,每年需交 ...

  6. jxl 创建excel

    public static void performanceExcel(String sCurrPath,List<Record> list, String begin,String en ...

  7. VC字符串处理整理

    场景: 1.在存储数据时有时接口需要合并字符串值,并以某些特殊字符来合并部分,到需要的时候再分割它.如一些数值,人名等. 2.C++有strtok,stringstream和find函数来实现分割.可 ...

  8. MySQL主从复制备份

    前言 数据库实时备份的需求很常见,MySQL本身提供了 Replication 机制,摘译官方介绍如下: MySQL Replication 可以将一个主数据库中的数据同步到一个或多个从数据库中.并且 ...

  9. 在windows系统下安装oracle 11g

     oracle 11g 安装在windows server 2012 系统下. 最近,需要配置数据库,要求在windows操作系统下,安装oracle 11g 数据库,因为以前没有安装过,所以成功后, ...

  10. CComSafeArray

    https://blog.csdn.net/tangaowen/article/details/6554640