安装qiankun
yarn add qiankun \# 或者 npm i qiankun -S
- src目录下新建qiankun文件夹
- qiankun目录下新建apps.js内容如下
import { useRouter } from 'vue-router'; /** *微应用apps * @name: 微应用名称 - 具有唯一性 * @entry: 微应用入口.必选 - 通过该地址加载微应用, * @container: 微应用挂载节点 - 微应用加载完成后将挂载在该节点上 * @activeRule: 微应用触发的路由规则 - 触发路由规则后将加载该微应用 */ //子应用列表 const _apps = []; for (const key in import.meta.env) { if (key.includes('VITE_APP_SUB_')) { const name = key.split('VITE_APP_SUB_')[1]; const obj = { name, entry: import.meta.env[key], container: '#content', activeRule: name, props: { router: useRouter() } }; _apps.push(obj); } } export const apps = _apps;
- qiankun目录下新建state.js内容如下
/** *公共数据 */ import {initGlobalState} from 'qiankun'; import {store} from '/@/store'; import {router} from '/@/router'; import { getToken } from '/@/utils/auth'; //定义传入子应用的数据 export function getProps() { return { data: { publicPath:'/', token: getToken(), store, router } } } /** * 定义全局状态,并返回通信方法,在主应用使用,微应用通过 props 获取通信方法。 * @param state 主应用穿的公共数据 */ export function initGlState(info = {userName: 'admin'}) { // 初始化state const actions = initGlobalState(info); // 设置新的值 actions.setGlobalState(info); // 注册 观察者 函数 - 响应 globalState 变化,在 globalState 发生改变时触发该 观察者 函数。 actions.onGlobalStateChange((newState, prev) => { // state: 变更后的状态; prev 变更前的状态 console.info("newState", newState) console.info("prev", prev) for (const key in newState) { console.info("onGlobalStateChange", key) } }); }
- qiankun目录下新建index.js内容如下
/** * qiankun配置 */ import {registerMicroApps, setDefaultMountApp, start, runAfterFirstMounted, addGlobalUncaughtErrorHandler} from 'qiankun'; import {apps} from './apps'; import {getProps, initGlState} from './state'; /** * 重构apps */ function filterApps() { apps.forEach((item) => { //主应用需要传递给微应用的数据。 item.props = getProps(); //微应用触发的路由规则 item.activeRule = genActiveRule('/' + item.activeRule); }); return apps; } /** * 路由监听 * @param {*} routerPrefix 前缀 */ function genActiveRule(routerPrefix) { return location => location.pathname.startsWith(routerPrefix); } /** * 微应用注册 */ function registerApps() { const _apps = filterApps(); registerMicroApps(_apps, { beforeLoad: [ loadApp => { console.log('before load', loadApp); } ], beforeMount: [ mountApp => { console.log('before mount', mountApp); } ], afterMount: [ mountApp => { console.log('before mount', mountApp); } ], afterUnmount: [ unloadApp => { console.log('after unload', unloadApp); } ] }); // 设置默认子应用,与 genActiveRule中的参数保持一致 // setDefaultMountApp(); // 第一个微应用 mount 后需要调用的方法,比如开启一些监控或者埋点脚本。 runAfterFirstMounted(() => console.log('开启监控')); // 添加全局的未捕获异常处理器。 addGlobalUncaughtErrorHandler(event => console.log(event)); // 定义全局状态 initGlState(); //启动qiankun start(); } export default registerApps;
- 引入qiankun注册文件
vue3-admin-jeecg/src/layouts/default/content/index.vue中加入如下代码
<div id="content" class="app-view-box" v-if="openQianKun=='true'"></div>
onMounted(() => {
//注册openQianKun
if (openQianKun=='true') {
if (!window.qiankunStarted) {
window.qiankunStarted = true;
registerApps();
}
}
});
- 添加全局控制开关
vue3-admin-jeecg/.env 文件中加入qiankun全局控制开关
VITE_GLOB_APP_OPEN_QIANKUN=true
- 修改打包输出位
修改vue3-admin-jeecg/build/constant.ts中outputDir内容定义,将打包内容输出到qiankun-vue3-jeecg文件夹下main目录下
export const OUTPUT_DIR = '../dist/main';
- 添加全局启动打包文件(package.json) 存放位置如下图
文件内容如下
{
"name": "qiankun-jeecg",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"install": "npm-run-all install:* ",
"install:main": "cd ant-design-jeecg-vue && npm install",
"install:sub01": "cd jeecg-app-1 && npm install ",
"start": "npm-run-all start:* ",
"start:main": "cd ant-design-jeecg-vue && start cmd /k npm run serve",
"start:sub01": "cd jeecg-app-1 && start cmd /k npm run serve",
"build": "npm-run-all build:* ",
"build:main": "cd ant-design-jeecg-vue && npm run build",
"build:sub01": "cd jeecg-app-1 && npm run build"
},
"devDependencies": {
"npm-run-all": "^4.1.5"
}
}
#微前端qiankun应用,命名必须以VITE_APP_SUB_开头,jeecg-app-1为子应用的项目名称,也是子应用的路由父路径 VITE_APP_SUB_jeecg-app-1 = '//localhost:8083'
可能遇到的问题
就是如果子应用不改变路由的情况下,主应用是可以正常切换的,但当子应用改变路由后,则路由报错,给出的错误原因是在路由前面增加了一个undefined这个问题经过网上搜查资料发现是因为vue-router导致的
主应用中通过router.beforeEach判断history.state数据结构是否异常,如果是,则重新设置
if (window.history.state === null) {
history.replaceState({
back: from.path,
current: to.path,
forward: null,
position: NaN,
replaced: false,
scroll: null
}, '/' + to.path)
}
而子应用中每次切换路由后手动调用一次window.history.pushState,以保证主应用能正常使用
window.history.pushState(null,'');