本文章仅记录我的开发历程,想要干货的请参考我下面的链接,本文可以略过了
- tabs标签逻辑实现:手把手带你在微前端(qiankun)中实现多页签功能(路由keepalive) - 掘金 (juejin.cn)
- 子应用页面缓存功能实现:sansui-orz/qiankun-admin: 微前端中后台系统模版。使用了qiankun, Vue3, Webpack5, Vite4, React18, TypeScript等最新主流技术框架,开箱即用的中后台前端解决方案。 页面tabs缓存,模块联邦,应用全局状态管理。 (github.com)
- vue-router的回退bug:github.com/umijs/qiank...
react主应用增加tabs标签的逻辑
这里可以参考上面第一个链接,但是由于文章里的页面缓存实现是在父应用里实现的多例子应用,即每个页面都是一个单独的实例,页面多的情况下应该会有性能问题。所以只抄袭借鉴了这个文章里的tabs标签页的操作逻辑,页面缓存功能另寻出路。
子应用增加页面缓存
参考上面第二个链接,实现思路为在子应用unmount
时,不调用vue或react的卸载事件,将rootDom append到document.body里面,并用样式隐藏,子应用重新mount
时,将隐藏的rootDom显示
vue子应用
入口改造
ts
let rootDom: Element | undefined;
async function render(props: any) {
console.log("render");
const { container } = props;
const root = createApp(VueApp);
root.use(createPinia());
root.use(router);
root.provide("appStore", props.appStore);
rootDom = container ? container.querySelector("#root") : document.getElementById("root");
root.mount(rootDom!);
}
renderWithQiankun({
update() {},
mount(props) {
console.log("mount", props);
props?.setLoading(false);
if (!rootDom) {
render(props);
} else {
rootDom!.setAttribute("display", "block");
props.container?.parentNode?.appendChild(rootDom!);
}
},
bootstrap() {
console.log("bootstrap");
},
unmount(props) {
console.log("unmount", props);
rootDom!.setAttribute("display", "none");
document.body.appendChild<Element>(rootDom!);
},
});
keep-alive实现
js
//layout.vue
<template>
<RouterView v-slot="{ Component }">
<KeepAlive v-show="canCache">
<component :is="Component"></component>
</KeepAlive>
<component v-if="canCache" :is="Component"></component>
</RouterView>
</template>
react子应用
入口改造
ts
//请参考vue的
由于react没有原生的KeepAlive
组件,使用的是react-activation
来实现页面缓存功能,如果需要实现类似vue的max
API,可以参考这里
ts
// layout.tsx
import { KeepAlive, useAliveController } from "react-activation";
const MAX_CACHE = 10;
const keys: Set<string> = new Set();
const LayoutInner = () => {
const routes = useLocation();
const controller = useAliveController();
const pushKeys = (key: string) => {
const cachePath = keys.has(key);
if (cachePath) {
keys.delete(key);
keys.add(key);
} else {
keys.add(key);
if (keys.size > MAX_CACHE) {
const deleteKey = keys.values().next().value;
keys.delete(deleteKey);
controller.drop(deleteKey);
}
}
};
const dom = <Outlet />;
if (canCache)) {
pushKeys(routes.pathname);
return (
<KeepAlive id={routes.pathname} name={routes.pathname}>
{dom}
</KeepAlive>
);
}
return dom;
};
遇到的问题
- vue子应用回退异常:原因是
vue-router
依赖了history.state,具体的原因请看这里 - 场景:从子级页面增加一项数据,回到一级页面,由于做了页面缓存,新增的数据并不会出现在页面上,是一个合理的bug。合理的解决方案:参考ProTable - 高级表格 - ProComponents (ant.design)的
revalidateOnFocus
,在窗口聚焦时重新请求接口 refreshTab
刷新tab:原贴里使用了改变key的方式rerender页面,但是我们由于有页面缓存,页面加载时的接口等不会重新请求,还没有想到一个同时兼容vue和react的方案,暂时使用window.location.reload()
代替- ......