互相通信,主-子,子-主,子-子
(1)方式一,使用官方的initGlobalState来实现
官方使用教程中,只是在mount的生命周期里去调用该方法,在实际的项目中需要在其他页面中调用全局参数,所以我们通过写一个actions.js将这个全局状态获取出来,方便在各个地方使用。这里参考的是基于qiankun的微前端最佳实践(图文并茂)对actions的封装。
首先在主应用创建actions.js,将全局状态实例导出来(导出来是为了在主应用自己使用)
import { initGlobalState, MicroAppStateActions } from 'qiankun';
const initialState = {};
const actions = initGlobalState(initialState);//定义全局状态
export default actions;
使用实例的方法,该实例有以下几个方法,可以设置,获取全局状态。
- onGlobalStateChange: (callback: OnGlobalStateChangeCallback, fireImmediately?: boolean) => void, 在当前应用监听全局状态,有变更触发 callback,fireImmediately = true 立即触发 callback
- setGlobalState: (state: Record<string, any>) => boolean, 按一级属性设置全局状态,微应用中只能修改已存在的一级属性
- offGlobalStateChange: () => boolean,移除当前应用的状态监听,微应用 umount 时会默认调用
\
\
onGlobalStateChange在每一次全局状态改变的时候都会调用, 第二个参数为 true,表示立即执行一次观察者函数
主应用设置,主应用获取
import actions from '../shared/actions';
...
const userInfo = {
userName: '黄马泥',
token: '123456789',
userId: '1',
role: 'admin',
};//微应用中只能修改已存在的一级属性,也就是这里定义的
//设置全局状态
actions.setGlobalState(userInfo);
//获取全局状态
actions.onGlobalStateChange((state, prev) => {
// state: 变更后的状态; prev 变更前的状态
console.log(state, prev);
});
主应用设置,子应用获取,子应用修改,主应用和其他子应用获取。
主应用的配置就是上面配置,如果子应用需要使用,按照以下配置
首先创建action.js文件
// micro-app-vue/src/shared/actions.js
function emptyAction() {
// 警告:提示当前使用的是空 Action
console.warn('Current execute action is empty!');
}
class Actions {
// 默认值为空 Action
actions = {
onGlobalStateChange: emptyAction,
setGlobalState: emptyAction,
};
/**
* 设置 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;
然后获取主应用的实例,在render中通过 actions.setActions(props)获取
这里解释下,为什么没有在主应用的props中传入actions对象,这里就能获取。因为initGlobalState调用以后,在render打印出 props会发现,props里自己就会有了onGlobalStateChange和setGlobalState,所以在上述actions.js的封装里,我们直接就把这两个属性映射给了 actions 对象。
function render(props = {}) {
console.log(props);
actions.setActions(props); //获取主应用的全局状态实例
const { container } = props;
instance = createApp(App);
instance
.use(store)
.use(router)
.use(Antd)
.mount(container ? container.querySelector('#app') : '#app');
instance.config.globalProperties.mainRouter = props.router;
console.log('主应用rouer', props.router);
}
接下来就可以使用这个对象进行获取和设置的操作了,在子应用的VUE页面下就可以这么写,随后调用changeName就可以改变主应用和其他所有子应用中的userName值了。
调用了setGlobalState方法后,其他所有 主应用 和 子应用 中的onGlobalStateChange方法都会调用一次,这样就可以同步到所有的应用中了。但是必须 主应用先进行第一次设置 。
setup(){
const userName = ref({});
let globalState = '';
//获取全局状态
actions.onGlobalStateChange((state) => {
// console.log(state);
console.log(state.userName);
userName.value = state.userName;
globalState = state;
}, true);第二个参数为 true,表示立即执行一次观察者函数
//修改全局状态
const changeName = ()=>{
globalState.userName = '王马泥';
actions.setGlobalState(globalState);
}
return{
userName,
changeName
}
}
(2)方式二,使用主应用的vuex实现(演示代码为vue2.x)
实现思路:在主应用创建vuex,通过props把vuex传递到子应用中,同时子应用通过Vue. prototype.xxx全局变量的方式定义自己的vuex,这样就可以不影响 子应用 使用vuex。
实现步骤
1.创建主应用的vuex,通过store/index.js 创建
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
// 定义一个name,以供全局使用
name: '',
// 定义一个number,以供全局使用
number: 0,
// 定义一个list,以供全局使用
list: [
{ id: 1, name: '111' },
{ id: 2, name: '222' },
{ id: 3, name: '333' },
]
},
mutations: { // 增加nutations属性
setName(state , name) { // 增加一个mutations的方法,方法的作用是让num从0变成5,state是必须默认参数
state.name = name;
}
},
});
export default store;
2、通过props把vuex传递到子应用中
{
name: "vueApp", // 应用的名字
entry: "http://localhost:10000/", //
container: "#vue", // 要渲染到的容器名id
activeRule: "/vue", // 通过哪一个路由来激活
props:{
store
}//参数
},
3、子应用中使用
首先从render中获取,然后设置自己的store,取名为microStore
这里注意设置Vue.observable响应式
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import Vuex from 'vuex'
import microStore from './store'
Vue.prototype.microStore = microStore;
Vue.config.productionTip = false
Vue.use(Vuex);
let instance = null;
function render(props) {
const store = props.store;//主应用的store
Vue.observable(store);//将共享store设置为响应式,否则子应用的store中的值不会改变
// props 组件通信
instance = new Vue({
router,
store,
render: h => h(App)
}).$mount('#app') // 这里是挂载到自己的HTML中,基座会拿到这个挂载后的HTML,将其插入进去
}
if (!window.__POWERED_BY_QIANKUN__) { // 如果是独立运行,则手动调用渲染
render();
}
if(window.__POWERED_BY_QIANKUN__){ // 如果是qiankun使用到了,则会动态注入路径
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
// 根据 qiankun 的协议需要导出 bootstrap/mount/unmount
export async function bootstrap(props) {
};
export async function mount(props) {
render(props);
};
export async function unmount(props) {
instance.$destroy();
};
在vue页面中调用
<template>
<div class="home">
<img alt="Vue logo" src="../assets/logo.png">
<div class="head">主应用store:{{$store.state.name}}</div>
<div>自己的store:{{microStore.state.name}}</div>
<button @click="logout">登出</button>
</div>
</template>
<script>
// @ is an alias to /src
export default {
methods:{
logout(){
this.$store.commit('setName','王七八九');
}
}
}
</script>
<style scoped>
.head{
background-color: green;
color: white;
}
</style>
总结
到目前为止,用qiankun搭建了一个基本的框架,实现了主子应用之间的通信,互相的跳转
\