 应用间通信
          应用间通信
        
 # 划分子应用
在开始介绍 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 可以触发所有的 观察者 函数,从而达到组件间通信的效果。 我们从上图可以看出,我们可以先注册 观察者 到观察者池中,然后通过修改 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 来获取用户信息,最后在页面中显示用户信息。代码过于简单就不展示了
