Regular進階: 跨組件通訊

本文由做者鄭海波受權網易雲社區發佈。node

背景
在組件化不斷深刻的大環境下,不管使用哪一種 MDV 框架都最終會遇到一個頭疼的問題,就是「跨組件通訊」。redux

下圖是個簡單的例子安全

這裏包含「事件通訊」和「數據通訊」兩個維度。服務器

事件傳遞框架

爲了將事件 click 從 <LeafNode /> 傳遞到最外層組件,須要依次經過 <SubNode /> 和 等可能本不關心這個事件的組件(即便例子裏已經使用了proxy的簡化語法)組件化

數據傳遞性能

爲了從 <Top /> 傳遞 title 這個 prop 到 <LeafNode /> , 須要層層跨越 、<SubNode /> 這些本不須要關心 title屬性 的組件。ui

以上處理方式除了帶來性能上的損耗以外,更麻煩的就是形成了可維護性的急速降低。this

顯而易見的事件通訊解決方案
最直接的作法就是引入一個「中介者」,簡而言之就是一個全局的「跳板」,下例就是一個事件中介者code

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.$parent或this.$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來解決跨組件的數據通訊的方式

免費領取驗證碼、內容安全、短信發送、直播點播體驗包及雲服務器等套餐

更多網易技術、產品、運營經驗分享請訪問網易雲社區。

文章來源: 網易雲社區

相關文章
相關標籤/搜索