前言:基于qiankun实现微前端入门(持续更新)
1:主应用(基座的实现)
基础目录
├── qiankun-main // 基座
└── qiankun-vue-child // vue子应用
app.uve
<template>
<div class="app">
<span><router-link to="/">点击跳转到父页面</router-link></span>
<span><router-link to="/vue">点击跳转到子页面</router-link></span>
<router-view />
<div id="vue"></div> <!-- 重点2:子应用容器 id -->
</div>
</template>
路由配置文件
//配置history模式剩余和vue写法一样
const router = new VueRouter({
mode:'history',
base:'',
routes
})
//vue.config.js 配置
module.exports ={
devServer: {
port: 8085,
headers: { // 重点1: 允许跨域访问子应用页面
'Access-Control-Allow-Origin': '*',
}
}
}
main.js
import {registerMicroApps, start} from 'qiankun'
import microApps from './mirco-app' //子应用注册文件
import '@/store/globalStore'//主应用状态管理器
registerMicroApps(microApps, { //注册配置文件中的子应用
beforeLoad: app => {
console.log('before load app.name====>>>>>', app.name)
},
beforeMount: [
app => {
console.log('[LifeCycle] before mount %c%s', 'color: green;', app.name)
},
],
afterMount: [
app => {
console.log('[LifeCycle] after mount %c%s', 'color: green;', app.name)
}
],
afterUnmount: [
app => {
console.log('[LifeCycle] after unmount %c%s', 'color: green;', app.name)
},
],
})
子应用配置文件
import action from '@/store/globalStore'
const microApps = [
{
name: 'qiankun-vue-child',
entry: '//192.168.254.87:8888',
activeRule: '/vue',
container: '#vue', // 子应用挂载的div
props: {
routerBase: '/vue', // 下发路由给子应用,子应用根据该值去定义qiankun环境下的路由
getGlobalState: action.getGlobalState //主应用给子应用共享的数据
}
}
]
export default microApps
主应用状态管理器封装
import {initGlobalState } from 'qiankun'
import Vue from 'vue'
//父应用的初始state
// Vue.observable是为了让initialState变成可响应
let globalState =Vue.observable({
user:{
name:'mool',
age:10
}
})
const actions = initGlobalState(globalState)
actions.onGlobalStateChange((state,prev)=>{
console.log('这里处理状态变更逻辑:', state,prev)
})
// 定义一个获取state的方法下发到子应用
actions.getGlobalState = (key) => {
// 有key,表示取globalState下的某个子级对象
// 无key,表示取全部
console.log('globalState:', globalState)
return key ? globalState[key] : globalState
}
export default actions;
2:子应用(qiankun-vue-child)
main.js
import globalRegister from './store/globalStore'
import routes from './router' //将注册路由提取到main.js中进行
import '../public-path'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
Vue.config.productionTip = false
let instance = null
function render(props = {}) { //获取主应用通过props传来的路由路径
const {container, routerBase} = props
const router = new VueRouter({
//区分是否在qiankun环境下,qiankun环境下加载主应用传入的路由路径
base: window.__POWERED_BY_QIANKUN__ ? routerBase : '/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()
}
//子应用需暴露出以下生命周期
export async function bootstrap() {
console.log('bootstrap')
}
export async function mount(props) {
globalRegister(store, props)//注册vuex-module
render(props)
}
export async function unmount() {
instance.$destroy()
instance.$el.innerHTML = ''
instance = null
}
config配置文件
const { name } = require('./package.json')//名称需与主应用中注册的名称对应
module.exports = {
configureWebpack: {
output: {
library: `${name}-[name]`,
libraryTarget: 'umd',
jsonpFunction: `webpackJsonp_${name}`,
}
},
devServer: {
port: process.env.VUE_APP_PORT, // 在.env中VUE_APP_PORT=7788,与父应用的配置一致
headers: {
'Access-Control-Allow-Origin': '*' // 主应用获取子应用时跨域响应头
}
}
}
子应用状态管理器(注册到vuex-module`)
function registerGlobalModule(store, props = {}) {
if (!store || !store.hasModule) {
return;
}
// 获取初始化的state
const initState = props.getGlobalState && props.getGlobalState() || {
user: {}
};
// 将父应用的数据存储到子应用中,命名空间固定为global
if (!store.hasModule('global')) {
const globalModule = {
namespaced: true,
state: initState,
actions: {
// 子应用改变state并通知父应用
setGlobalState({ commit }, payload) {
console.log('payload:',payload )
commit('setGlobalState', payload);
commit('emitGlobalState', payload);
},
// 初始化,只用于mount时同步父应用的数据
initGlobalState({ commit }, payload) {
console.log('payloadpayloadpayload:', payload)
commit('setGlobalState', payload);
},
},
mutations: {
setGlobalState(state, payload) {
// eslint-disable-next-line
console.log('statestatestate:', state,payload)
if (payload.key){
state = Object.assign(state[payload.key], payload.data);
}else{
state = Object.assign(state, payload);
}
},
// 通知父应用
emitGlobalState(state) {
if (props.setGlobalState) {
props.setGlobalState(state);
}
},
},
};
store.registerModule('global', globalModule);
} else {
// 每次mount时,都同步一次父应用数据
store.dispatch('global/initGlobalState', initState);
}
}
export default registerGlobalModule;
子父应用的通信
import {mapState, mapActions} from 'vuex'
export default {
name: 'child',
components: {},
computed: {
...mapState('global', {
user: state => state.user, // 获取父应用的user信息
}),
},
methods: {
...mapActions('global', ['setGlobalState']),
update() {
this.setGlobalState({key:'user', data:{name: '张三',age:1}})
}
}
}