应用间通信
# 划分子应用
在开始介绍 qiankun
的应用通信之前,我们需要先了解微前端架构如何划分子应用。
在微前端架构中,我们应该按业务划分出对应的子应用,而不是通过功能模块划分子应用。这么做的原因有两个:
- 在微前端架构中,子应用并不是一个模块,而是一个独立的应用,我们将子应用按业务划分可以拥有更好的可维护性和解耦性。
- 子应用应该具备独立运行的能力,应用间频繁的通信会增加应用的复杂度和耦合度。 综上所述,我们应该从业务的角度出发划分各个子应用,尽可能减少应用间的通信,从而简化整个应用,使得我们的微前端架构可以更加灵活可控。
# Actions
通信
这是qiankun
官方提供的应用间通信方式
# 通信原理
qiankun
内部提供了initGlobalState
方法用于注册MicroAppStateActions
实例用于通信,该实例有三个方法,分别是:
onGlobalStateChange
:(callback: OnGlobalStateChangeCallback, fireImmediately?: boolean) => void
, 在当前应用监听全局状态,有变更触发callback
,fireImmediately = true
立即触发callback
setGlobalState: (state: Record<string, any>) => boolean
, 按一级属性设置全局状态,微应用中只能修改已存在的一级属性offGlobalStateChange: () => boolean
,移除当前应用的状态监听,微应用umount
时会默认调用 我们来画一张图来帮助大家理解(见下图) 我们从上图可以看出,我们可以先注册 观察者 到观察者池中,然后通过修改 globalState 可以触发所有的 观察者 函数,从而达到组件间通信的效果。
# 实战教学
我们将Actions
通信和vuex
结合起来使用
# 主应用的工作
首先,我们在主应用中注册一个 MicroAppStateActions 实例并导出,代码实现如下:
// src/shared/actions.js
import { initGlobalState } from "qiankun";
const initialState = {};
const actions = initGlobalState(initialState);
export default actions;
2
3
4
5
6
7
本例中我们需要通信的数据是用户信息,所以我们封装一下 发送用户信息
和 监听用户信息的函数
// src/utils/action.js
//导入刚刚注册并导出的actions实例
import actions from "@/shared/actions";
//设置用户信息全局状态
export function sendUserInfo(info){
//属性名为userInfo
actions.setGlobalState({ userInfo:info });
}
//监听全局的用户信息
export function watchUserInfo(func,bool){
//注册 观察者 函数
actions.onGlobalStateChange(func,bool);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
然后主应用登录后,使用vuex
存储userInfo
,然后在App.vue
中监听userInfo
//src/App.vue
import {sendUserInfo,watchUserInfo} from "@/utils/actions";
import { mapGetters } from 'vuex'
export default {
name: 'App',
components:{
layout: () => import("@/layout/index.vue")
},
data(){
return {
}
},
computed: {
...mapGetters([
'userInfo'
])
},
watch:{
userInfo(newVal,oldVal){
//监听到userInfo改变的时候发送userInfo
if(newVal){
sendUserInfo(newVal)
}
}
},
mounted() {
//mounted的时候发送一遍userInfo
sendUserInfo(this.userInfo)
},
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 子应用的工作
我们已经完成了主应用的登录功能,将 userInfo
信息记录在了 globalState
中。现在,我们进入子应用,使用 userInfo
获取用户信息并展示在页面中。
首先来改造我们的Vue
子应用,首先我们设置一个 Actions
实例,代码实现如下:
//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;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
创建 actions
实例后,需要为其注入真实 Actions
。在入口文件 main.js
的 render
函数中注入,代码实现如下:
// src/main.js
import actions from "@/shared/actions";
//....
//....
/**
* 渲染函数
* 两种情况:主应用生命周期钩子中运行 / 微应用单独启动时运行
*/
function render(props) {
if (props) {
// 注入 actions 实例
actions.setActions(props);
}
//.......
}
//....
//.....
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
从上面的代码可以看出,挂载子应用时将会调用 render
方法,在render
方法中将主应用的 actions
实例注入即可。
然后子应用中也封装一下 发送用户信息
和 监听用户信息的函数
// src/utils/action.js
//导入actions实例
import actions from "@/shared/actions";
//设置用户信息全局状态
export function sendUserInfo(info){
//属性名为userInfo
actions.setGlobalState({ userInfo:info });
}
//监听全局的用户信息
export function watchUserInfo(func,bool){
//注册 观察者 函数
actions.onGlobalStateChange(func,bool);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
然后在子应用 App.vue
页面中监听 globalState
中的 userInfo
,并存入子应用vuex
。代码实现如下:
// src/App.vue
import {watchUserInfo} from "@/utils/actions";
import { mapMutations } from 'vuex'
export default {
name: 'App',
data(){
return{
}
},
mounted() {
watchUserInfo((state, prevState) => {
// state: 变更后的状态; prevState: 变更前的状态
let {userInfo} = state
// 将userInfo 存入 vuex
this.setUserInfo(userInfo)
})
},
methods:{
...mapMutations({
setUserInfo: 'SET_USERINFO'
})
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
最后我们在子应用的 "获取主应用数据" 页面获取 vuex
中的 userInfo
,使用 userInfo
来获取用户信息,最后在页面中显示用户信息。代码过于简单就不展示了