1、安装 qiankun
npm i qiankun
2、创建入口文件register.js
import { registerMicroApps, start, initGlobalState } from 'qiankun'
import store from '@/store'
import { env } from '@/utils/config'
// 注册微应用通信示例
const initialState = {}
export const actions = initGlobalState(initialState)
// qiankun全局状态监听
// actions.onGlobalStateChange((state, prev) => {
// // state: 变更后的状态; prev 变更前的状态
// })
actions.setGlobalState({ fullScreen: false })
export let microApps = [
{
name: 'person',
entry: {
development: 'http://localhost:8080/',
sit: '',
production: '',
private: ''
}[env],
container: '#micro-app',
activeRule: '/micro-app/person',
meta: { // 做权限、菜单显示等逻辑处理
productCode: 'A',
name: '人员管理',
icon: require('@/assets/image/1.png'),
key: 'A',
}
},
{
name: 'permission',
entry: {
development: 'http://localhost:8081/',
sit: '',
production: '',
private: ''
}[env],
container: '#micro-app',
activeRule: '/micro-app/permission',
meta: {
productCode: 'B',
name: '权限管理',
icon: require('@/assets/image/2.png'),
key: 'B',
}
},
]
// qiankun配置
registerMicroApps(microApps, {
beforeMount: (app) => {
// 设置产品编码(解决回退产品编码不一致问题)
store.commit('user/SET_PRODUCT_CODE', app.meta.productCode)
}
})
start({
prefetch: false,
sandbox: {
experimentalStyleIsolation: true // 主子应用样式隔离
},
excludeAssetFilter: assetUrl => { // 指定部分特殊的动态加载的微应用资源(css/js) 不被 qiankun 劫持处理
// 自定义白名单链接
const whiteList = []
/**
* 白名单协议:子应用下如需要放行动态加载的css/js资源,可以在链接上带上参数 _custom-exclude_=MAIN
*/
const whiteWords = ['_custom-exclude_=MAIN'] // 白名单关键词:协议制定 _custom-exclude_=MAIN。
if (whiteList.includes(assetUrl)) {
return true
}
return whiteWords.some(w => {
return assetUrl.includes(w)
})
}
})
3、引入
main.js
// qiankun注册子应用
import './utils/register'
4、容器
layout
<template>
<div class="app-wrapper">
<div v-if="showHeader" class="app-header">
<Header />
</div>
<div id="micro-app" class="app-container">
<app-main class="app-main" />
</div>
</div>
</template>
<script>
import Header from './components/Header'
import AppMain from './components/AppMain.vue'
import { actions } from '@/utils/register'
export default {
name: 'Layout',
components: {
Header,
AppMain
},
data() {
return {
showHeader: true
}
},
created() {
if (this.$route.query.fullScreen === 'true') {
this.showHeader = false
}
},
mounted() {
this.listenGlobalState()
},
methods: {
listenGlobalState() {
// qiankun全局状态
actions.onGlobalStateChange((state) => {
if (state.fullScreen === true) {
this.showHeader = false
} else {
this.showHeader = true
}
})
}
}
}
</script>
<style lang="scss" scoped>
.app-wrapper {
height: 100%;
display: flex;
flex-direction: column;
.app-header {
height: 50px;
line-height: 50px;
}
.app-container {
width: 100%;
flex: 1;
height: 0;
.sidebar {
width: 210px;
background-color: rgb(48, 65, 86);
overflow: scroll;
}
.app-main {
flex: 1;
min-height: calc(100% - 50px);
width: 100%;
}
}
.app-container>div {
width: 100%;
}
}
</style>
Header
<template>
<el-menu
:default-active="activeIndex"
class="top-menu"
mode="horizontal"
@select="handleSelect"
>
<el-menu-item v-for="(item) in productList" :key="item.productCode" :index="item.productCode">{{ item.productName }}</el-menu-item>
</el-menu>
</template>
<script>
import { mapGetters } from 'vuex'
import mcroAppLink from '@/utils/mcroAppLink'
export default {
name: 'TopMenu',
data() {
return {
activeIndex: ''
}
},
computed: {
...mapGetters([
'productList',
'productCode'
])
},
watch: {
productCode: {
handler(val) {
this.activeIndex = val
},
immediate: true
}
},
methods: {
// 切换产品
handleSelect(val) {
let activeRule = mcroAppLink(val)
this.$router.push(activeRule)
}
}
}
</script>
AppMain
<template>
<section>
<transition name="fade-transform" mode="out-in">
<div id="app-vue">
<router-view :key="key" />
</div>
</transition>
</section>
</template>
<script>
export default {
name: 'AppMain',
computed: {
key() {
return this.$route.path
}
}
}
</script>