准备工作
使用vuecli新建两个应用,main_vue,app1,将main_vue作为主应用,app1为子应用。
main_vue安装阿里qiankun使用以下安装命令
npm i qiankun -S 或者 yarn add qiankun #
配置子应用
与src同级新增vue.config.js
//vue.config.js
const { name } = require('./package');
module.exports = {
devServer: {
port:9095,//启动端口
headers: {
'Access-Control-Allow-Origin': '*',//配置跨域
},
},
configureWebpack: {
output: {
library: `${name}-[name]`,
libraryTarget: 'umd', // 把微应用打包成 umd 库格式
jsonpFunction: `webpackJsonp_${name}`,
},
},
};
于main.js同级新建public-path.js
//public-path.js
if (window.__POWERED_BY_QIANKUN__) {
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
子应用router.js配置
//router.js
//不能在此处直接配置路由需每次加载子应用时配置路由
import Home from '../views/Home.vue'
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
]
export default router
子应用main.js配置
//main.js
import './public-path'; //导入public-path.js主要在于处理静态资源路径
import Vue from 'vue';
import VueRouter from 'vue-router';
import App from './App.vue';
import routes from './router';
import store from './store';
Vue.config.productionTip = false;
let router = null;
let instance = null;
function render(props = {}) {
const { container } = props;
//加载路由,之所以不在一个js页面配置是因为应用每次加载需要重新加载路由,否则当子应用卸载时再次加载会出现问题显示不出来
router = new VueRouter({
//主应用注册时子应用时activeRule需与此一致,此处为单独运行时默认路由前缀为/,在主应用运行时为/app-vue/
base: window.__POWERED_BY_QIANKUN__ ? '/app-vue/' : '/',
mode: 'history',
routes,
});
instance = new Vue({
router,
store,
render: (h) => h(App),
}).$mount(container ? container.querySelector('#app') : '#app');
}
// 独立运行时
if (!window.__POWERED_BY_QIANKUN__) {
render();
}
//以下为qiangun规定的需要暴露出来的3个生命周期
export async function bootstrap() {
console.log('[vue] vue app bootstraped');
}
export async function mount(props) {
console.log('[vue] props from main framework', props);
render(props);
}
export async function unmount() {
instance.$destroy();
instance.$el.innerHTML = '';
instance = null;
router = null;
}
配置主应用
主应用main.js配置
//main.js
import Vue from 'vue'
import { registerMicroApps, runAfterFirstMounted, setDefaultMountApp, start } from 'qiankun';
import App from './App.vue';
Vue.config.productionTip = false
let app = null;
//类似单例模式,初次加载时渲染主应用框架,之后每次注册子应用时会再次触发该函数
function render({ appContent, loading }) {
if (!app) {
app = new Vue({
el: '#my-app', //public文件下的index.html中根节点id需要相应修改
data() {
return {
content: appContent,
loading,
};
},
render(h) {
return h(App, {
props: {
content: this.content,
loading: this.loading,
},
});
},
});
} else {
app.content = appContent;
app.loading = loading;
}
}
//路由处理
function genActiveRule(routerPrefix) {
return location => location.pathname.startsWith(routerPrefix);
}
//首次渲染主应用
render({ loading: true });
const request = url =>
fetch(url, {
referrerPolicy: 'origin-when-cross-origin',
});
// 传入子应用的数据
let msg = {
data: {
auth: false
},
fns: [
{
name: "_LOGIN",
_LOGIN() {
}
}
]
};
//注册子应用,name:子应用名字作为唯一标识,entry子应用路径,render触发渲染,
注意activeRule需要与子应用路由的base一致
registerMicroApps(
[
{ name: 'app-vue/', entry: '//localhost:8081', render, activeRule: genActiveRule('/app-vue/') },
],
{
beforeLoad: [
//子应用加载前
app => {
window.console.log('before load', app);
},
],
beforeMount: [
//进入子应用时触发
app => {
window.console.log('before mount', app);
},
],
afterUnmount: [
//离开子应用时触发
app => {
window.console.log('after unload', app);
},
],
},
{
fetch: request,
},
);
setDefaultMountApp('/vuecli');//进入主应用时加载的默认路由
runAfterFirstMounted(() => window.console.info('first app mounted')); //首个子应用加载完
start({ prefetch: true, fetch: request }); //启动
主应用app.js配置
//app.js
<template>
<section>
<header class="header">
<nav>
<ol>
<li><a @click="goto('app1', '/app-vue/')">app1</a></li>
</ol>
</nav>
</header>
<div v-if="loading">loading</div>
<div class="appContainer" v-html="content">content</div>
</section>
</template>
<script>
export default {
name: 'framework',
props: {
loading: Boolean,
content: String,
},
methods: {
goto(title, href) {
window.history.pushState({}, title, href);
},
},
};
</script>
<style scoped>
.header {
}
.appContainer {
margin-top: 50px;
}
</style>