We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
父应用通过setData发送数据到子应用,子应用使用addDataListener在接收相同数据时不触发回调。本质原因官网也有提及,在setData时会对对象第一层结构字段作检测,如果数据相同则不会发送:
在项目的issues中,有很多相关的issue提到数据通信问题,如 #1356 #1389 #1409 等。
基本原理:在micro-app提供的setGlobalData(data)方法中,不涉及iframe间通讯,不涉及数据JSON拷贝解析等,故我们可以往data中传递函数。 实现步骤:
setGlobalData(data)
Emitter
gData
emitter
microApp.start()
microApp.setGlobalData(gData)
window.microApp.getGlobalData()
注意,这个emitter在实现时不同于常见的发布订阅,需对订阅的事件类型(name)作特殊处理,以区分多个不同应用(主应用/子应用)。
name
父应用:
var emitter = { // 注册某个应用对某个类型事件的监听 on(type, listener, appname) {}, // 取消某个应用的所有注册监听 offApp(appname) {}, // 取消所有应用对于某个类型事件的注册 offType(type) {}, // 取消某个应用对某个事件类型的注册 offApp(appname, type, listener) {}, // 在某个应用上触发某个事件 emit(appname, type, ...args) {}, // 对所有应用触发某个事件 emitType(type, ...args) {}, // 扩展事件类型,以支持区分多个应用 formatEvtName(appname, type) {}, }; // 启动应用 microApp.setGlobalData({ emitter: emitter }); microApp.start(); // 使用 microApp.getGlobalData().emitter.on('sometype', (data) => { console.log('父应用收到消息:', data) }, 'app-parent'); microApp.getGlobalData().emitter.emit('app-child', 'sometype', '来自父应用的消息');
子应用:
// 使用 window.microApp.getGlobalData().emitter.on('sometype', (data) => { console.log('子应用收到消息:', data) }, 'app-child'); window.microApp.getGlobalData().emitter.emit('app-parent', 'sometype', '来自子应用的消息');
为确保内存安全,需在子应用的生命周期中适当地清理事件及其回调。
// 父应用 microApp.start({ lifeCycles: { unmount(e, appname) { microApp.getGlobalData().emitter.offApp(appname); } } });
// 此EventEmitter实现了最基本的发布订阅模型 import EventEmitter from 'path/to/emitter' interface IListener { (...args: any[]): any } // 封装一个强化版的支持多应用的发布订阅模型 export default class MicroAppEventEmitter { private emitter = new EventEmitter() /** * 注册(应用)对某个类型事件的监听 * @param type * @param listener * @param appName */ public on(type: string, listener: IListener, appName?: string): void { if (appName) { this.emitter.on(this.formatEvtName(appName, type), listener) } else { this.emitter.on(type, listener) } } /** * 取消某个子应用的所有注册事件 * @param appName */ public offApp(appName: string) { const types = this.emitter.getEvtNames() types.forEach((t) => { const [name] = this.decodeEvtName(t) if (name === appName) { this.emitter.off(t) } }) } /** * 取消所有应用对于某个事件类型的注册 * @param type */ public offType(type: string, listener?: IListener) { const types = this.emitter.getEvtNames() types.forEach((t) => { const [, tType] = this.decodeEvtName(t) if (type === tType) { this.emitter.off(t, listener) } }) } /** * 取消某个应用对某个事件类型的注册 * @param appName * @param type * @param listener */ public off(appName: string, type: string, listener?: IListener): void { this.emitter.off(this.formatEvtName(appName, type), listener) } /** * 触发某个类型事件(对所有应用生效) * @param type * @param args */ public emitType(type: string, ...args: unknown[]) { const types = this.emitter.getEvtNames() types.forEach((t) => { const [, tType] = this.decodeEvtName(t) if (tType === type) { this.emitter.emit(t, ...args) } }) } /** * 触发指定应用的某个类型事件 * @param appName * @param type * @param args */ public emit(appName: string, type: string, ...args: unknown[]): void { this.emitter.emit(this.formatEvtName(appName, type), ...args) } public once(appName: string, type: string, listener: IListener): void { const l: IListener = (...args) => { listener(...args) this.off(appName, type, l) } this.on(type, l, appName) } public clear(): void { this.emitter.clear() } private formatEvtName(appName: string, type: string) { return `${appName}${MicroAppEventEmitter.delimiter}${type}` } private decodeEvtName(evtName: string): [string | undefined, string] { const [appName, type] = evtName.split(MicroAppEventEmitter.delimiter) if (!type) { return [undefined, appName] } return [appName, type] } private static delimiter = '::' } // 使用 microApp.setGlobalData({ emitter: new MicroAppEventEmitter() })
虽然这里说的是emitter发布订阅模型,但大家可以基于此步骤实现自己的setState方法(异步/同步)或其他逻辑。而不需要使用micro-app怪异的addDataListener方法。
setState
addDataListener
The text was updated successfully, but these errors were encountered:
No branches or pull requests
背景
同类问题参考
在项目的issues中,有很多相关的issue提到数据通信问题,如 #1356 #1389 #1409 等。
父应用向子应用发送消息,或子应用向父应用发送消息,消息总是可达的
基本原理:在micro-app提供的
setGlobalData(data)
方法中,不涉及iframe间通讯,不涉及数据JSON拷贝解析等,故我们可以往data中传递函数。实现步骤:
Emitter
发布订阅工具;gData
,该数据包含一个emitter
实例;microApp.start()
前,调用microApp.setGlobalData(gData)
初始化全局数据;window.microApp.getGlobalData()
获取emitter
实例;emitter
的发布/订阅方法;emitter
的发布/订阅方法。注意,这个emitter在实现时不同于常见的发布订阅,需对订阅的事件类型(
name
)作特殊处理,以区分多个不同应用(主应用/子应用)。数据通信伪代码
父应用:
子应用:
内存安全
为确保内存安全,需在子应用的生命周期中适当地清理事件及其回调。
emitter伪代码
扩展
虽然这里说的是emitter发布订阅模型,但大家可以基于此步骤实现自己的
setState
方法(异步/同步)或其他逻辑。而不需要使用micro-app怪异的addDataListener
方法。The text was updated successfully, but these errors were encountered: