登录
注册
开源
企业版
高校版
搜索
帮助中心
使用条款
关于我们
开源
企业版
高校版
私有云
Gitee AI
NEW
我知道了
查看详情
登录
注册
代码拉取完成,页面将自动刷新
开源项目
>
WEB应用开发
>
WebUI组件/框架
&&
捐赠
捐赠前请先登录
取消
前往登录
扫描微信二维码支付
取消
支付完成
支付提示
将跳转至支付宝完成支付
确定
取消
Watch
不关注
关注所有动态
仅关注版本发行动态
关注但不提醒动态
54
Star
443
Fork
179
徐小夕
/
H5_Dooring
代码
Issues
4
Pull Requests
0
Wiki
统计
流水线
服务
Gitee Pages
质量分析
Jenkins for Gitee
腾讯云托管
腾讯云 Serverless
悬镜安全
阿里云 SAE
Codeblitz
我知道了,不再自动展开
更新失败,请稍后重试!
Issues
/
详情
移除标识
内容风险标识
本任务被
标识为内容中包含有代码安全 Bug 、隐私泄露等敏感信息,仓库外成员不可访问
Dooring低代码平台组件间通信方案复盘
待办的
#I6AK9N
徐小夕
拥有者
创建于
2023-01-14 19:52
## 背景介绍 3年前我开发了一款零代码搭建平台 **H5-Dooring**, 主要目的是想用更低的成本, 更快的效率, 上线 **web** 页面(其实是不想写重复的代码了,写麻了). 好在陆陆续续折腾了3年, 目前已经可以满足基本的页面设计和搭建能力, 并能快速上线页面. 之前也在社区分享了很多**低代码**和**零代码**的技术实现, 接下来继续和大家聊聊低代码平台中组件与组件之间的通信方案设计. ### 可视化搭建平台的基本能力 根据我自己设计可视化搭建平台的经验, 其需要具备最最基本的两个能力: - **静态页面设计能力**(也就是可以用可视化平台制作我们想要的页面的能力) - **组件交互能力**(制作好静态页面之后, 页面元素能具备一定的交互, 比如跳转链接, 打开弹窗等) 以上的能力可以让我们将页面通过拖拽的方式搭建出来: [![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/da3a18328e7744f69f5320b1838f1553~tplv-k3u1fbpfcp-zoom-1.image)](http://h5.dooring.cn/h5_plus) 虽然这已经可以满足很多展示型的需求, 但是仍然存在局限性, 比如可视化平台的组件与组件之间, 没办法相互通信. ### 更灵活自主的可视化搭建平台 这里给大家举一个实际的场景, 比如我们要做一个转盘H5页面, 它由转盘组件和按钮组件组成, 当点击按钮时, 转盘开始运动: ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2794723a289b48079e82d42bf36051ee~tplv-k3u1fbpfcp-zoom-1.image) 这种场景就需要转盘组件和按钮组件相互通信, 来实现交互功能. 所以在可视化搭建平台中, 如果能实现组件间的通信, 那将覆盖更多的业务场景, 从而为个人或者企业带来更大的价值. ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/be174ee9719d4711b93dfdd109a52b08~tplv-k3u1fbpfcp-zoom-1.image) 接下来我将和大家分享一下低代码平台中组件间通信的几种方案, 共大家学习参考. ## 组件间通信的几种实现方案 ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2e72619c715242dcae83f8e2a393794a~tplv-k3u1fbpfcp-zoom-1.image) 说到组件通信我们也许并不陌生, 比如在 `vue` 或者 `React` 框架中, 经常会涉及到父子组件通信以及组件与组件间的通信, 常用的方案也有很多, 比如: 1. `props/$emit` 2. 子组件向父组件传值 3. eventBus(`$emit/$on`) 4. vuex / redux 5. `$attrs/$listeners` 6. provide/inject 当然还有很多方式能帮我们实现传统组件间的通信, 那我们在低代码组件中, 也可以参考类似的方式来实现, 但是唯一的区别是需要设计一套规则, 来保证组件间通信可以通过用户配置的方式来运转. 接下来我们来分析几种低代码组件间的通信方案. ### 1.websocket 在设计组件通信方案前, 我们需全局维护一个公共的状态, 拿 **H5-Dooring可视化平台** 举例, 我们用 `redux` 管理公共状态, 组件间通信本质就是触发公共状态的更新: ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/de9dd94399b345bf9e8e3fc47d0b1e6a~tplv-k3u1fbpfcp-zoom-1.image) 为了保证低代码组件库足够纯净, 比如不应该在组件里连接 `redux`, 所以我们需要把 `redux` 触发器 `dispatch` 放在页面的全局, 这里就可以用 `websocket`, 在组件里触发 `socket` 指令, 在页面全局来监听, 并触发 `dispatch` : ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c28ffc523e6346deb6db343d6fcd7400~tplv-k3u1fbpfcp-zoom-1.image) 当然使用 `socket` 的方式仍然会让低代码组件库负重前行(虽然能实现更自由的通信场景, 比如组件自更新, 生命周期回调, 控制业务钩子等), 因为我们不得不为其搭建 `socket` 服务, 并且需要为其设计稳定的通信桥梁, 比如 `socket` 心跳连接等. ### 2.iframe通信 postmessage 利用 `iframe` 的 `postmessage` 等 `API` 虽然也能实现组件间通信, 但是我们需要设计一套通信机制, 保证 `iframe` 能接受组件传送的指令, 并对外暴露共享状态: ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2d9d7231361d44469bd8a9b9181185fd~tplv-k3u1fbpfcp-zoom-1.image) 我们从 `Iframe` 的通信模式可以发现它不仅可以作为中间桥梁起到通信作用, 有点类似于 eventBus的模式, 而且还可以实现页面间的通信, 比如目前很多**微前端架构**的底层支持也有采用 iframe 来设计的. 但是对于更细粒度的低代码组件来说, 有点小题大作了. 接下来给大家分享一下 `iframe` 通信的基本代码实现: ```js // 父页面和子页面通信 // A.html (父) <iframe src="http://h5.dooring.cn/h5_plus" frameborder="1" id="Bframe"></iframe> const msg = { name: "H5-Dooring" } window.onload = () => { // 自动调用必须放在onload中,通过事件调用则不用 // let frame = document.querySelector("#Bframe").contentWindow let frame = window.frames[0] frame.postMessage(msg, "http://h5.dooring.cn/preview") } // B.html window.addEventListener("message", (e) => { console.log(e.data) console.log(e.origin) console.log(e.source) }) // 子页面和父页面通信 // A.html (父) <iframe src="http://h5.dooring.cn/h5_plus" frameborder="1" id="Bframe"></iframe> window.addEventListener("message", (e) => { console.log(e.data) console.log(e.origin) console.log(e.source) }) // B.html const msg = { name: "Dooring H5" } window.top.postMessage(msg, "http://h5.dooring.cn/preview") ``` ### 3.Event Emitters `Event Emitters` 的方式我觉得是最适合低代码组件间通信的方案, 类似于 `js` 里的事件监听机制, 我们可以给 `dom` 绑定监听, 并暴露事件给用户来实现手动触发机制. (虽然不一定是用户手动触发, 也有一种情况是逻辑触发, 比如当页面某个组件到达某一状态的时候, 后自动触发事件, 来改变其他组件的状态) `Event Emitters` 类似一种观察者模式, 我们可以利用 javascript 的设计模式来实现它, 并在组件内部来监听或者触发, 一个简单的实现如下: ```js interface Events { [key: string]: Function[]; } export class EventEmitter { public events: Events; constructor(events?: Events) { this.events = events || {}; } public subscribe(name: string, cb: Function) { (this.events[name] || (this.events[name] = [])).push(cb); return { unsubscribe: () => this.events[name] && this.events[name].splice(this.events[name].indexOf(cb) >>> 0, 1) }; } public emit(name: string, ...args: any[]): void { (this.events[name] || []).forEach(fn => fn(...args)); } } ``` 具体设计流程有点像我之前设计的 `iframe` 通信架构, 不过使用起来会更简单: ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/fbc4c5fc866a410f98b43ae66f8b0559~tplv-k3u1fbpfcp-zoom-1.image) ## 低代码组件事件队列设计 以上只实现了组件的通信, 并没有将通信和实际的应用场景结合起来, 比如低代码用户需要如何操作,才能实现组件通信. 这里我之前也设计了一套模型: ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/af7b9e4c4f294c8bb5502f76cf2b8db5~tplv-k3u1fbpfcp-zoom-1.image) 每个组件都有一套事件列表, 用户可以给一个组件添加多个交互事件, 在第代码内部通过循环遍历来依次触发事件队列: ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4c6d01e8b6be4e219020599eeebd02cd~tplv-k3u1fbpfcp-zoom-1.image) 事件通信就可以用上面介绍的 **Event Emitters**来实现, 具体的低代码模式可以参考我之前的项目: [H5-Dooring可视化低代码平台](https://github.com/MrXujiang/h5-Dooring) ## 总结 后续我会继续和大家分享一下 **H5-Dooring** 低代码的更多实践和思考, 如果大家对可视化低代码感兴趣也可以参考我的**低代码可视化**专栏. 下一篇文章我会和大家分享一下低代码印章组件的实现方案, 大家有更多好的建议也可以随时和我反馈. :::: column ::: column-left **H5-dooring低代码** ![H5-dooring低代码](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ffc8126231ad4ab8ac58b2116dce3cad~tplv-k3u1fbpfcp-zoom-1.image) ::: ::: column-right **V6.Dooring可视化大屏搭建平台** ![V6.Dooring可视化大屏搭建平台](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/47f34d1a4f764a0688543638fb7995ae~tplv-k3u1fbpfcp-zoom-1.image) ::: ::::
## 背景介绍 3年前我开发了一款零代码搭建平台 **H5-Dooring**, 主要目的是想用更低的成本, 更快的效率, 上线 **web** 页面(其实是不想写重复的代码了,写麻了). 好在陆陆续续折腾了3年, 目前已经可以满足基本的页面设计和搭建能力, 并能快速上线页面. 之前也在社区分享了很多**低代码**和**零代码**的技术实现, 接下来继续和大家聊聊低代码平台中组件与组件之间的通信方案设计. ### 可视化搭建平台的基本能力 根据我自己设计可视化搭建平台的经验, 其需要具备最最基本的两个能力: - **静态页面设计能力**(也就是可以用可视化平台制作我们想要的页面的能力) - **组件交互能力**(制作好静态页面之后, 页面元素能具备一定的交互, 比如跳转链接, 打开弹窗等) 以上的能力可以让我们将页面通过拖拽的方式搭建出来: [![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/da3a18328e7744f69f5320b1838f1553~tplv-k3u1fbpfcp-zoom-1.image)](http://h5.dooring.cn/h5_plus) 虽然这已经可以满足很多展示型的需求, 但是仍然存在局限性, 比如可视化平台的组件与组件之间, 没办法相互通信. ### 更灵活自主的可视化搭建平台 这里给大家举一个实际的场景, 比如我们要做一个转盘H5页面, 它由转盘组件和按钮组件组成, 当点击按钮时, 转盘开始运动: ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2794723a289b48079e82d42bf36051ee~tplv-k3u1fbpfcp-zoom-1.image) 这种场景就需要转盘组件和按钮组件相互通信, 来实现交互功能. 所以在可视化搭建平台中, 如果能实现组件间的通信, 那将覆盖更多的业务场景, 从而为个人或者企业带来更大的价值. ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/be174ee9719d4711b93dfdd109a52b08~tplv-k3u1fbpfcp-zoom-1.image) 接下来我将和大家分享一下低代码平台中组件间通信的几种方案, 共大家学习参考. ## 组件间通信的几种实现方案 ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2e72619c715242dcae83f8e2a393794a~tplv-k3u1fbpfcp-zoom-1.image) 说到组件通信我们也许并不陌生, 比如在 `vue` 或者 `React` 框架中, 经常会涉及到父子组件通信以及组件与组件间的通信, 常用的方案也有很多, 比如: 1. `props/$emit` 2. 子组件向父组件传值 3. eventBus(`$emit/$on`) 4. vuex / redux 5. `$attrs/$listeners` 6. provide/inject 当然还有很多方式能帮我们实现传统组件间的通信, 那我们在低代码组件中, 也可以参考类似的方式来实现, 但是唯一的区别是需要设计一套规则, 来保证组件间通信可以通过用户配置的方式来运转. 接下来我们来分析几种低代码组件间的通信方案. ### 1.websocket 在设计组件通信方案前, 我们需全局维护一个公共的状态, 拿 **H5-Dooring可视化平台** 举例, 我们用 `redux` 管理公共状态, 组件间通信本质就是触发公共状态的更新: ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/de9dd94399b345bf9e8e3fc47d0b1e6a~tplv-k3u1fbpfcp-zoom-1.image) 为了保证低代码组件库足够纯净, 比如不应该在组件里连接 `redux`, 所以我们需要把 `redux` 触发器 `dispatch` 放在页面的全局, 这里就可以用 `websocket`, 在组件里触发 `socket` 指令, 在页面全局来监听, 并触发 `dispatch` : ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c28ffc523e6346deb6db343d6fcd7400~tplv-k3u1fbpfcp-zoom-1.image) 当然使用 `socket` 的方式仍然会让低代码组件库负重前行(虽然能实现更自由的通信场景, 比如组件自更新, 生命周期回调, 控制业务钩子等), 因为我们不得不为其搭建 `socket` 服务, 并且需要为其设计稳定的通信桥梁, 比如 `socket` 心跳连接等. ### 2.iframe通信 postmessage 利用 `iframe` 的 `postmessage` 等 `API` 虽然也能实现组件间通信, 但是我们需要设计一套通信机制, 保证 `iframe` 能接受组件传送的指令, 并对外暴露共享状态: ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2d9d7231361d44469bd8a9b9181185fd~tplv-k3u1fbpfcp-zoom-1.image) 我们从 `Iframe` 的通信模式可以发现它不仅可以作为中间桥梁起到通信作用, 有点类似于 eventBus的模式, 而且还可以实现页面间的通信, 比如目前很多**微前端架构**的底层支持也有采用 iframe 来设计的. 但是对于更细粒度的低代码组件来说, 有点小题大作了. 接下来给大家分享一下 `iframe` 通信的基本代码实现: ```js // 父页面和子页面通信 // A.html (父) <iframe src="http://h5.dooring.cn/h5_plus" frameborder="1" id="Bframe"></iframe> const msg = { name: "H5-Dooring" } window.onload = () => { // 自动调用必须放在onload中,通过事件调用则不用 // let frame = document.querySelector("#Bframe").contentWindow let frame = window.frames[0] frame.postMessage(msg, "http://h5.dooring.cn/preview") } // B.html window.addEventListener("message", (e) => { console.log(e.data) console.log(e.origin) console.log(e.source) }) // 子页面和父页面通信 // A.html (父) <iframe src="http://h5.dooring.cn/h5_plus" frameborder="1" id="Bframe"></iframe> window.addEventListener("message", (e) => { console.log(e.data) console.log(e.origin) console.log(e.source) }) // B.html const msg = { name: "Dooring H5" } window.top.postMessage(msg, "http://h5.dooring.cn/preview") ``` ### 3.Event Emitters `Event Emitters` 的方式我觉得是最适合低代码组件间通信的方案, 类似于 `js` 里的事件监听机制, 我们可以给 `dom` 绑定监听, 并暴露事件给用户来实现手动触发机制. (虽然不一定是用户手动触发, 也有一种情况是逻辑触发, 比如当页面某个组件到达某一状态的时候, 后自动触发事件, 来改变其他组件的状态) `Event Emitters` 类似一种观察者模式, 我们可以利用 javascript 的设计模式来实现它, 并在组件内部来监听或者触发, 一个简单的实现如下: ```js interface Events { [key: string]: Function[]; } export class EventEmitter { public events: Events; constructor(events?: Events) { this.events = events || {}; } public subscribe(name: string, cb: Function) { (this.events[name] || (this.events[name] = [])).push(cb); return { unsubscribe: () => this.events[name] && this.events[name].splice(this.events[name].indexOf(cb) >>> 0, 1) }; } public emit(name: string, ...args: any[]): void { (this.events[name] || []).forEach(fn => fn(...args)); } } ``` 具体设计流程有点像我之前设计的 `iframe` 通信架构, 不过使用起来会更简单: ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/fbc4c5fc866a410f98b43ae66f8b0559~tplv-k3u1fbpfcp-zoom-1.image) ## 低代码组件事件队列设计 以上只实现了组件的通信, 并没有将通信和实际的应用场景结合起来, 比如低代码用户需要如何操作,才能实现组件通信. 这里我之前也设计了一套模型: ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/af7b9e4c4f294c8bb5502f76cf2b8db5~tplv-k3u1fbpfcp-zoom-1.image) 每个组件都有一套事件列表, 用户可以给一个组件添加多个交互事件, 在第代码内部通过循环遍历来依次触发事件队列: ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4c6d01e8b6be4e219020599eeebd02cd~tplv-k3u1fbpfcp-zoom-1.image) 事件通信就可以用上面介绍的 **Event Emitters**来实现, 具体的低代码模式可以参考我之前的项目: [H5-Dooring可视化低代码平台](https://github.com/MrXujiang/h5-Dooring) ## 总结 后续我会继续和大家分享一下 **H5-Dooring** 低代码的更多实践和思考, 如果大家对可视化低代码感兴趣也可以参考我的**低代码可视化**专栏. 下一篇文章我会和大家分享一下低代码印章组件的实现方案, 大家有更多好的建议也可以随时和我反馈. :::: column ::: column-left **H5-dooring低代码** ![H5-dooring低代码](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ffc8126231ad4ab8ac58b2116dce3cad~tplv-k3u1fbpfcp-zoom-1.image) ::: ::: column-right **V6.Dooring可视化大屏搭建平台** ![V6.Dooring可视化大屏搭建平台](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/47f34d1a4f764a0688543638fb7995ae~tplv-k3u1fbpfcp-zoom-1.image) ::: ::::
评论 (
0
)
徐小夕
创建了
任务
登录
后才可以发表评论
状态
待办的
待办的
进行中
已完成
已关闭
负责人
未设置
标签
未设置
标签管理
里程碑
未关联
未关联
Pull Requests
未关联
未关联
关联的 Pull Requests 被合并后可能会关闭此 issue
分支
未关联
未关联
master
开始日期   -   截止日期
-
置顶选项
不置顶
置顶等级:高
置顶等级:中
置顶等级:低
优先级
不指定
严重
主要
次要
不重要
参与者(1)
JavaScript
1
https://gitee.com/lowcode-china/h5_-dooring.git
git@gitee.com:lowcode-china/h5_-dooring.git
lowcode-china
h5_-dooring
H5_Dooring
点此查找更多帮助
搜索帮助
Git 命令在线学习
如何在 Gitee 导入 GitHub 仓库
Git 仓库基础操作
企业版和社区版功能对比
SSH 公钥设置
如何处理代码冲突
仓库体积过大,如何减小?
如何找回被删除的仓库数据
Gitee 产品配额说明
GitHub仓库快速导入Gitee及同步更新
什么是 Release(发行版)
将 PHP 项目自动发布到 packagist.org
评论
仓库举报
回到顶部
登录提示
该操作需登录 Gitee 帐号,请先登录后再操作。
立即登录
没有帐号,去注册