✨背景
在新老平台过渡期间,两个平台的用户要分别在不同的平台办理业务或者查看数据,而且还要在两个平台之前来回登录,给用户造成一定的困扰。不仅如此在技术升级中,为了做到系统平滑流畅的升级,也是需要一种方案在不破坏目前架构和用户体验的基础上,完成这一系列操作。这个时候大家肯定是最先想到通过iframe嵌入的方式把两个平台融合在一起,但是这样的方式有些弊端。那如何做到丝滑、无感知的嵌入呢,下面就一起来探讨一下最近实践。
✨技术选型
iframe | qiankun | 无界 | |
---|---|---|---|
优点 | 1. 使用简单 2. 可以做到应用直接完全隔离 | 由于这玩意我也没研究过。以下是网上的总结: 1. 监听路由自动的加载、卸载当前路由对应的子应用 2. 完备的沙箱方案 3. 路由保持,浏览器刷新、前进、后退,都可以作用到子应用应用间通信简单,全局注入 | 1. 通过组件方式来使用为前端,主应用只需引入组件即可 2. 可以完美的做到应用隔离 3. 可以做到路由、状态的保活 4. 子应用的适配性极高,几乎不需任何多余配置 5. 通讯机制完善,提供多种通讯方式,直接上手可用 |
缺点 | 1. 无法做到保持子应用状态 2. 完全隔离,使得子应用和主应用之间有割裂感 3. 通讯需要自己封装使用 | 1. 基于路由匹配,无法同时激活多个子应用,也不支持子应用保活 2. 改造成本较大 3. css 沙箱无法绝对的隔离,js 沙箱在某些场景下执行性能下降严重 4. 无法支持 vite 等 ESM 脚本运行 | 1. 子应用初始化加载时控制台会抛出错误 2. 站点需要跨域支持 3. 有些css定位还是会出现移位的情况 |
通过以上优缺点分析比较,故选定使用成本最低的无界方案来进行处理
✨通讯方式
props方式
主应用可以通过组件上的props属性给子应用传递数据和方法
<WujieVue name="xxx" url="http://xxx.xxx.xxx" :props="{data:'data',method:{method}}">
子应用通过window.$wujie.props来接受
window.$wujie.props.data
window.$wujie.props.method()
widnow方式
设置变量
// 主应用
window.mainValue = 'mainValue'
// 子应用
window.subValue = 'subValue'
获取变量
// 主应用调用子应用
window.document.querySelector("iframe[name=xxx]").contentWindow.subValue
// 子应用调用主应用
window.parent.mainValue
eventBus式
主应用使用方式
// 如果使用wujie
import { bus } from "wujie";
// 如果使用wujie-vue
import WujieVue from "wujie-vue";
const { bus } = WujieVue;
// 如果使用wujie-react
import WujieReact from "wujie-react";
const { bus } = WujieReact;
// 主应用监听事件
bus.$on("事件名字", function (arg1, arg2, ...) {});
// 主应用发送事件
bus.$emit("事件名字", arg1, arg2, ...);
// 主应用取消事件监听
bus.$off("事件名字", function (arg1, arg2, ...) {});
子应用使用方式
// 子应用监听事件
window.$wujie?.bus.$on("事件名字", function (arg1, arg2, ...) {});
// 子应用发送事件
window.$wujie?.bus.$emit("事件名字", arg1, arg2, ...);
// 子应用取消事件监听
window.$wujie?.bus.$off("事件名字", function (arg1, arg2, ...) {});
✨平台改造项
主应用:
安装
# vue2 框架
npm i wujie-vue2 -S
# vue3 框架
npm i wujie-vue3 -S
main.js 引入
// vue2
import WujieVue from "wujie-vue2";
// vue3
import WujieVue from "wujie-vue3";
const { bus, setupApp, preloadApp, destroyApp } = WujieVue;
Vue.use(WujieVue);
使用
<WujieVue name="唯一id" url="子应用地址" ></WujieVue>
子应用:
- 如不使用单例模式或预加载则无需任何改造
- 生命周期改造,具体改造方式可以自行查看官方文档
✨注意事项
- 由于嵌套后主应用和子应用的localstorage和cookie都是公用一套的,需要注意命名规范否则会发生覆盖问题
- 子应用一定要支持跨域的
✨避坑提醒
一、 子应用设置单例后,第二次进入子应用页面,路由不重载
- 解决方案:路由版本过高,目前使用3.4.9解决此问题
二、由于嵌入后dom结构会发生变化,会导致子应用有些css定位不准的问题
- 解决方案:主应用或者子应用最外层元素设置position: relative
三、vite4的子应用单例后,会在切换子应用的时候发生样式丢失问题
- 解决方案:使用plugins插件方案解决
<WujieVue name="xxx" url="http://xxx.xxx.xxx" :props="{data:'data',method:{method}}" :plugins="plugins">
computed: {
plugins() {
return [
{
patchElementHook(element, iframeWindow) {
if (element.nodeName === 'STYLE') {
element.insertAdjacentElement = function (_position, ele) {
iframeWindow.document.head.appendChild(ele);
};
}
},
},
];
},
},