1、安裝 qiankun
npm i qiankun
2、創(chuàng)建入口文件register.js
import { registerMicroApps, start, initGlobalState } from 'qiankun'
import store from '@/store'
import { env } from '@/utils/config'
// 注冊微應(yīng)用通信示例
const initialState = {}
export const actions = initGlobalState(initialState)
// qiankun全局狀態(tài)監(jiān)聽
// actions.onGlobalStateChange((state, prev) => {
// // state: 變更后的狀態(tài); prev 變更前的狀態(tài)
// })
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: { // 做權(quán)限、菜單顯示等邏輯處理
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: '權(quán)限管理',
icon: require('@/assets/image/2.png'),
key: 'B',
}
},
]
// qiankun配置
registerMicroApps(microApps, {
beforeMount: (app) => {
// 設(shè)置產(chǎn)品編碼(解決回退產(chǎn)品編碼不一致問題)
store.commit('user/SET_PRODUCT_CODE', app.meta.productCode)
}
})
start({
prefetch: false,
sandbox: {
experimentalStyleIsolation: true // 主子應(yīng)用樣式隔離
},
excludeAssetFilter: assetUrl => { // 指定部分特殊的動態(tài)加載的微應(yīng)用資源(css/js) 不被 qiankun 劫持處理
// 自定義白名單鏈接
const whiteList = []
/**
* 白名單協(xié)議:子應(yīng)用下如需要放行動態(tài)加載的css/js資源,可以在鏈接上帶上參數(shù) _custom-exclude_=MAIN
*/
const whiteWords = ['_custom-exclude_=MAIN'] // 白名單關(guān)鍵詞:協(xié)議制定 _custom-exclude_=MAIN。
if (whiteList.includes(assetUrl)) {
return true
}
return whiteWords.some(w => {
return assetUrl.includes(w)
})
}
})
3、引入
main.js
// qiankun注冊子應(yīng)用
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全局狀態(tài)
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: {
// 切換產(chǎn)品
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>