文章目录
- 一、原理
- 1、setGlobalState:
- 2、onGlobalStateChange:
- 3、offGlobalStateChange:
- 4、图解
- 二、示例
- 主应用
- 1、在父应用中使用initGlobalState设置全局状态actions并导出供其他组件使用。
- 2、在main.js中引入actions实例并在注册子应用时通过props传递全局状态actions:
- 3、主应用中的组件要修改全局状态actions,就在此组件中引入actions实例
- 子应用
- 1、在子应用中配置一个空的actions实例为以后重新赋值从主应用中传递过来的actions:
- 2、然后在mounted的生命周期里注入actions实例:
- 3、子应用向主应用发送数据(子应用中修改数据,可以在主应用中监听到)
- 4、子应用在mounted钩子函数中注册qiankun的观察者函数
- 三、效果图
一、原理
qiankun 内部提供了 initGlobalState 方法用于注册 MicroAppStateActions 实例用于通信,该实例有三个方法,分别是onGlobalStateChange、setGlobalState、offGlobalStateChange。
1、setGlobalState:
设置 globalState - 设置新的值时,内部将执行 浅检查,如果检查到 globalState 发生改变则触发通知,通知到所有的 观察者 函数。
- 语法:
setGlobalState: (state) => boolean, //按一级属性设置全局状态,微应用中只能修改已存在的一级属性(就是用来修改全局状态的
2、onGlobalStateChange:
注册 观察者 函数 - 响应 globalState 变化,在 globalState 发生改变时触发该 观察者 函数。
- 语法:
onGlobalStateChange: (callback) => void //在当前应用监听全局状态,有变更触发 callback,fireImmediately = true 立即触发 callback
3、offGlobalStateChange:
取消 观察者 函数 - 该实例不再响应 globalState 变化。
- 语法:
offGlobalStateChange: () => boolean //移除当前应用的状态监听,微应用 umount 时会默认调用
4、图解
我们从上图可以看出,我们可以先注册 观察者 到观察者池中,然后通过修改 globalState 可以触发所有的观察者函数,从而达到组件间通信的效果。
二、示例
本示例介绍的是子应用中通过路由守卫,把当前的路由面包屑名称传到主应用中,主应用展示面包屑功能。
主应用
1、在父应用中使用initGlobalState设置全局状态actions并导出供其他组件使用。
actions.js
// 此action文件为定义微应用之间全局状态
// 引入qiankun的应用间通信方法initGlobalStateimport { initGlobalState } from 'qiankun';const initalState = {// 这里可以写初始化数据
}//初始化state
const actions = initGlobalState(initalState)export default actions;
2、在main.js中引入actions实例并在注册子应用时通过props传递全局状态actions:
main.js
import actions from './micro/actions'
// 注册的应用列表
registerMicroApps([{name: 'sub2',//应用名字entry: '//localhost:8082', //子应用的启用地址container: '#app-vue', //子应用所展示的地址 在App.vue中设置id为app-vueactiveRule: '/sub2', //路由地址// 通过props实现通信传递值props: {actions}},{name: 'sub1',//应用名字entry: '//localhost:8081', //子应用的启用地址container: '#app-vue', //子应用所展示的地址 在App.vue中设置id为app-vueactiveRule: '/sub1', //路由地址},
]);
3、主应用中的组件要修改全局状态actions,就在此组件中引入actions实例
app.vue
<template><div id="app"><div class="top"></div><div class="box"><div class="left"><el-menu :default-active="$route.path" router class="el-menu-vertical-demo" @open="handleOpen"@close="handleClose"><MenuItem :menu-list="menuList"></MenuItem></el-menu></div><div class="right"><div class="bread"><el-breadcrumb separator-class="el-icon-arrow-right"><el-breadcrumb-item v-for="(item,index) in crumb" :key="index">{{item.name}}</el-breadcrumb-item></el-breadcrumb></div><div class="main"><router-view></router-view><div id="app-vue"></div></div></div></div></div>
</template><script>
import actions from '@/micro/actions'
export default {components: {MenuItem},name: "App",data() {return {menuList:[],crumb:[]};},
mounted() {//修改全局的actionslet crumb=[]actions.setGlobalState({ crumb })console.log("主应用app的actions:",actions)//主应用监听参数变化,接受参数,展示面包屑功能actions.onGlobalStateChange((state, prevState) => {console.log("主应用app观察者,改变前的state为:", prevState);console.log("主应用app观察者,改变后的state为:", state);if(state?.crumb){this.crumb=state.crumb}else{this.crumb=[]}})}
</script>
子应用
配置子应用的全局状态Actions,子应用中的全局状态必须要跟主应用中的全局状态变量属性名相同,比如主应用中全局状态变量为{token: “main”},则子应用中也需要保证在setGloabalState时也需要设定相同的变量名。
1、在子应用中配置一个空的actions实例为以后重新赋值从主应用中传递过来的actions:
actions.js
function emptyAction() {// 警告:提示当前使用的是空 Actionconsole.warn("Current execute action is empty!");
}class Actions {// 默认值为空 Actionactions = {onGlobalStateChange: emptyAction,setGlobalState: emptyAction};constructor() {}/*** 设置 actions*/setActions(actions) {this.actions = actions;}/*** 映射*/onGlobalStateChange(...args) {return this.actions.onGlobalStateChange(...args);}/*** 映射*/setGlobalState(...args) {return this.actions.setGlobalState(...args);}
}const actions = new Actions();
export default actions;
2、然后在mounted的生命周期里注入actions实例:
main.js
import actions from './actions'function render(props = {}) {const { container } = props;if(props){actions.setActions(props)}instance = new Vue({router,render: (h) => h(App),}).$mount(container ? container.querySelector('#app') : '#app');//主应用中设置的id
}
3、子应用向主应用发送数据(子应用中修改数据,可以在主应用中监听到)
router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import HomeView from '../views/HomeView.vue'import actions from '@/actions'Vue.use(VueRouter)const routes = [{path: "/",redirect: "home"},{path: '/home',name: 'home',component: HomeView,meta:{fullPath:[{name:'首页'}]}},{path: '/about',name: 'about',component: () => import( /* webpackChunkName: "about" */ '../views/AboutView.vue'),meta:{fullPath:[{name:'首页'},{name:'关于'}]}}
]const router = new VueRouter({mode: 'history',base: window.__POWERED_BY_QIANKUN__ ? '/sub2/' : '/',routes
})// 通过路由守卫,把当前的路由面包屑名称传到主应用中
router.afterEach(to => {console.log("to:", to.meta.fullPath)actions.setGlobalState({ crumb: to.meta.fullPath });
})export default router
4、子应用在mounted钩子函数中注册qiankun的观察者函数
这里也可以监听主应用的参数
mounted(){actions.onGlobalStateChange((state) => {console.log("我是子应用,我检测到数据了:", state);}, true); //onGlobalStateChange的第二个参数设置为true,则会立即触发一次观察者函数}