mirror of
https://gitee.com/WeBank/fes.js.git
synced 2024-12-02 11:47:47 +08:00
feat: qiankun支持多页签keepalive (#117)
* fix: 判断页面权限的path统一从match中拿路由path * fix: qiankun主应用不改rootContainer * fix: 消除initialState为空时的warn * refactor: modifyCreateHistroy更改为modifyCreateHistory * fix: qiankun支持多页签keepalive
This commit is contained in:
parent
2ca3951c3f
commit
41b843396c
@ -4,10 +4,10 @@
|
||||
对于前端应用来说,权限就是页面、页面元素是否可见。
|
||||
|
||||
### 资源
|
||||
Fes.js 把页面、页面元素统一叫做资源,每个资源都有 `accessId`:
|
||||
- 页面的 `accessId` 默认是页面的路由 `path` 。比如页面 `pages/a.vue` 的路由 `path` 是 `/a`。当页面访问 `/a` 时会渲染当前页面,`/a` 也就是页面的 `accessId`。
|
||||
Fes.js 把页面、页面元素统一叫做资源,用资源 ID 来识别区分他们:
|
||||
- 页面的资源 ID 默认是页面的路由 `path` 。比如页面 `pages/a.vue` 的路由 `path` 是 `/a`。当页面访问 `/a` 时会渲染当前页面,`/a` 也就是页面的 `accessId`。
|
||||
|
||||
- 页面元素的 `accessId` 没有默认值,由我们自定义。
|
||||
- 页面元素的资源 ID 没有默认值,需要自定义。
|
||||
```vue
|
||||
<template>
|
||||
<access :id="accessId"> accessOnepicess1 <input /> </access>
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { plugin, ApplyPluginsType } from '@@/core/coreExports';
|
||||
// eslint-disable-next-line import/extensions
|
||||
import { access, install } from './core';
|
||||
|
||||
export function onRouterCreated({ router }) {
|
||||
@ -9,25 +10,35 @@ export function onRouterCreated({ router }) {
|
||||
initialValue: {}
|
||||
});
|
||||
if (to.matched.length === 0) {
|
||||
if (runtimeConfig.noFoundHandler && typeof runtimeConfig.noFoundHandler === 'function') {
|
||||
if (
|
||||
runtimeConfig.noFoundHandler
|
||||
&& typeof runtimeConfig.noFoundHandler === 'function'
|
||||
) {
|
||||
return runtimeConfig.noFoundHandler({
|
||||
router, to, from, next
|
||||
router,
|
||||
to,
|
||||
from,
|
||||
next
|
||||
});
|
||||
}
|
||||
return next(false);
|
||||
}
|
||||
let path;
|
||||
if (to.matched.length === 1) {
|
||||
path = to.matched[0].path;
|
||||
} else {
|
||||
path = to.path;
|
||||
}
|
||||
const canRoute = await access.hasAccess(path);
|
||||
// path是匹配路由的path,不是页面hash
|
||||
const canRoute = await access.hasAccess(
|
||||
to.matched[to.matched.length - 1].path
|
||||
);
|
||||
if (canRoute) {
|
||||
return next();
|
||||
}
|
||||
if (runtimeConfig.unAccessHandler && typeof runtimeConfig.unAccessHandler === 'function') {
|
||||
if (
|
||||
runtimeConfig.unAccessHandler
|
||||
&& typeof runtimeConfig.unAccessHandler === 'function'
|
||||
) {
|
||||
return runtimeConfig.unAccessHandler({
|
||||
router, to, from, next
|
||||
router,
|
||||
to,
|
||||
from,
|
||||
next
|
||||
});
|
||||
}
|
||||
next(false);
|
||||
|
@ -3,7 +3,7 @@
|
||||
main
|
||||
<FTabs v-model="activeKey">
|
||||
<FTabPane name="Tab 1" value="1">
|
||||
<MicroAppWithMemoHistory key="1" name="app1" url="/app1" />
|
||||
<MicroAppWithMemoHistory key="1" name="app1" url="/app1" a="1" />
|
||||
</FTabPane>
|
||||
<FTabPane name="Tab 2" value="2">
|
||||
<MicroAppWithMemoHistory key="2" name="app1" url="/app1/test" />
|
||||
|
@ -32,7 +32,7 @@
|
||||
"@fesjs/utils": "^2.0.4",
|
||||
"address": "^1.1.2",
|
||||
"lodash-es": "^4.17.15",
|
||||
"qiankun": "^2.4.4"
|
||||
"qiankun": "^2.7.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"npm-run-all": "^4.1.5"
|
||||
|
@ -26,6 +26,7 @@ export default function (api) {
|
||||
enableBy: () => isMasterEnable(api)
|
||||
});
|
||||
|
||||
// 避免跟子应用冲突
|
||||
api.modifyDefaultConfig(config => ({
|
||||
...config,
|
||||
mountElementId: defaultMainRootId
|
||||
|
@ -11,26 +11,26 @@ import { loadMicroApp } from "{{{QIANKUN}}}";
|
||||
import {mergeWith} from "{{{LODASH_ES}}}";
|
||||
// eslint-disable-next-line import/extensions
|
||||
import { getMasterOptions } from "./masterOptions";
|
||||
import { onBeforeRouteLeave } from "@@/core/coreExports";
|
||||
|
||||
async function unmountMicroApp(microApp) {
|
||||
if (microApp) {
|
||||
const status = microApp.getStatus();
|
||||
if(status === 'MOUNTED'){
|
||||
await microApp.unmount();
|
||||
}
|
||||
function unmountMicroApp(microApp) {
|
||||
if (!microApp) {
|
||||
return;
|
||||
}
|
||||
const status = microApp.getStatus();
|
||||
if (status === 'MOUNTED') {
|
||||
microApp.unmount();
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
export const MicroApp = defineComponent({
|
||||
props: {
|
||||
name: {
|
||||
type: String,
|
||||
required: true,
|
||||
required: true
|
||||
},
|
||||
settings: Object,
|
||||
lifeCycles: Object,
|
||||
props: Object,
|
||||
lifeCycles: Object
|
||||
},
|
||||
setup(props, { attrs }) {
|
||||
const {
|
||||
@ -40,8 +40,6 @@ export const MicroApp = defineComponent({
|
||||
...globalSettings
|
||||
} = getMasterOptions();
|
||||
|
||||
const stateForSlave = reactive({});
|
||||
|
||||
// 挂载节点
|
||||
const containerRef = ref(null);
|
||||
const microAppRef = ref();
|
||||
@ -68,6 +66,14 @@ export const MicroApp = defineComponent({
|
||||
|
||||
const propsFromParams = attrs;
|
||||
|
||||
const propsConfigRef = computed(() => {
|
||||
return {
|
||||
...propsFromConfigRef.value,
|
||||
...props.props,
|
||||
...propsFromParams
|
||||
};
|
||||
});
|
||||
|
||||
// 只有当name变化时才重新加载新的子应用
|
||||
const loadApp = () => {
|
||||
const appConfig = appConfigRef.value;
|
||||
@ -75,21 +81,21 @@ export const MicroApp = defineComponent({
|
||||
// 加载新的
|
||||
microAppRef.value = loadMicroApp(
|
||||
{
|
||||
name: name,
|
||||
// 保证唯一
|
||||
name: `${name}_${Date.now()}`,
|
||||
entry: entry,
|
||||
container: containerRef.value,
|
||||
props: {
|
||||
...propsFromConfigRef.value,
|
||||
...stateForSlave,
|
||||
...propsFromParams,
|
||||
},
|
||||
props: propsConfigRef.value
|
||||
},
|
||||
{
|
||||
...globalSettings,
|
||||
...(props.settings || {}),
|
||||
...(props.settings || {})
|
||||
},
|
||||
mergeWith({}, globalLifeCycles || {}, props.lifeCycles || {}, (v1, v2) =>
|
||||
concat(v1 ?? [], v2 ?? [])
|
||||
mergeWith(
|
||||
{},
|
||||
globalLifeCycles || {},
|
||||
props.lifeCycles || {},
|
||||
(v1, v2) => concat(v1 ?? [], v2 ?? [])
|
||||
)
|
||||
);
|
||||
};
|
||||
@ -106,9 +112,9 @@ export const MicroApp = defineComponent({
|
||||
updatingPromiseRef.value = updatingPromiseRef.value.then(
|
||||
() => {
|
||||
const canUpdate = (app) =>
|
||||
app?.update && app.getStatus() === "MOUNTED";
|
||||
app?.update && app.getStatus() === 'MOUNTED';
|
||||
if (canUpdate(microApp)) {
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
if (
|
||||
Date.now() -
|
||||
updatingTimestampRef.value <
|
||||
@ -127,11 +133,7 @@ export const MicroApp = defineComponent({
|
||||
}
|
||||
|
||||
// 返回 microApp.update 形成链式调用
|
||||
return microApp.update({
|
||||
...propsFromConfigRef.value,
|
||||
...stateForSlave,
|
||||
...propsFromParams,
|
||||
});
|
||||
return microApp.update(propsConfigRef.value);
|
||||
}
|
||||
}
|
||||
);
|
||||
@ -152,16 +154,10 @@ export const MicroApp = defineComponent({
|
||||
loadApp();
|
||||
});
|
||||
|
||||
onBeforeRouteLeave(async () => {
|
||||
return await unmountMicroApp(microAppRef.value);
|
||||
});
|
||||
|
||||
watch(()=>{
|
||||
return {...{}, ...propsFromConfigRef.value, ...stateForSlave, ...propsFromParams}
|
||||
}, () => {
|
||||
watch(propsConfigRef, () => {
|
||||
updateApp();
|
||||
});
|
||||
|
||||
return () => <div ref={containerRef}></div>;
|
||||
},
|
||||
}
|
||||
});
|
||||
|
@ -15,6 +15,7 @@ export const MicroAppWithMemoHistory = defineComponent({
|
||||
required: true
|
||||
},
|
||||
settings: Object,
|
||||
props: Object,
|
||||
lifeCycles: Object,
|
||||
url: String
|
||||
},
|
||||
|
@ -110,11 +110,7 @@ export function genUpdate() {
|
||||
export function genUnmount() {
|
||||
return async (props) => {
|
||||
const history = getHistory();
|
||||
history.destroy();
|
||||
if (cacheAppPromise) {
|
||||
const app = await cacheAppPromise;
|
||||
app.unmount();
|
||||
}
|
||||
history.destroy(); // 会触发app.unmount
|
||||
destroyRouter();
|
||||
const slaveRuntime = getSlaveRuntime();
|
||||
if (slaveRuntime.unmount) {
|
||||
|
@ -14,7 +14,7 @@ export function modifyClientRenderOpts(memo) {
|
||||
};
|
||||
}
|
||||
|
||||
export function modifyCreateHistroy(memo) {
|
||||
export function modifyCreateHistory(memo) {
|
||||
if (history.url) {
|
||||
return createMemoryHistory
|
||||
}
|
||||
|
@ -29,8 +29,8 @@ export default function (api) {
|
||||
'render',
|
||||
// 修改路由
|
||||
'patchRoutes',
|
||||
// 修改histror
|
||||
'modifyCreateHistroy',
|
||||
// 修改history
|
||||
'modifyCreateHistory',
|
||||
// 生成router时触发
|
||||
'onRouterCreated'
|
||||
]
|
||||
|
@ -27,7 +27,7 @@ const renderClient = (opts = {}) => {
|
||||
|
||||
const app = createApp(rootContainer);
|
||||
// initialState是响应式的,后期可以更改
|
||||
app.provide("initialState", reactive(initialState));
|
||||
app.provide("initialState", reactive(initialState ?? {}));
|
||||
|
||||
plugin.applyPlugins({
|
||||
key: 'onAppCreated',
|
||||
|
@ -14,7 +14,7 @@ export const createRouter = (routes) => {
|
||||
return router;
|
||||
}
|
||||
const createHistory = plugin.applyPlugins({
|
||||
key: 'modifyCreateHistroy',
|
||||
key: 'modifyCreateHistory',
|
||||
type: ApplyPluginsType.modify,
|
||||
args: {
|
||||
base: ROUTER_BASE
|
||||
|
Loading…
Reference in New Issue
Block a user