【qiankun+vue】微前端子应用之间的通信方式总结

一、qiankun 官方提供的通信方式 - Actions 通信。

适用场景:适合业务划分清晰,比较简单的微前端应用,一般来说使用第一种方案就可以满足大部分的应用场景需求。

1、api

qiankun内部使用initGlobalState(state)定义全局状态,该方法执行后返回一个MicroAppStateActions实例,实例中包含三个方法:

  • onGlobalStateChange
  • setGlobalState
  • offGlobalStateChange

注:

  • setGlobalState:设置 globalState - 设置新的值时,内部将执行 浅检查,如果检查到 globalState 发生改变则触发通知,通知到所有的 观察者 函数。
  • onGlobalStateChange:注册 观察者 函数 - 响应 globalState 变化,在 globalState 发生改变时触发该 观察者 函数。
  • offGlobalStateChange:取消 观察者 函数 - 该实例不再响应 globalState 变化。

2、具体实现

(1)主子应用配置

第一步:在主应用src目录下新建actions.ts文件,initGlobalState设置全局状态actions并导出供其他组件使用。

主应用:src/actions.ts

// 此action文件为定义微应用之间全局状态
// 引入qiankun的应用间通信方法initGlobalState
import { initGlobalState, MicroAppStateActions } from 'qiankun';

const initialState = {
  //这里可以写初始化数据
  // x:1
  project_id: ''
};

const actions: MicroAppStateActions = initGlobalState(initialState); //初始化state

export default actions;

第二步:在主应用全局引入人actions实例并在注册子应用时通过props传递全局状态actions。

common/config/registerAppConfig.ts

import actions from '@/actions';
export const registerAppConfig = [
    {
        name: 'databi',
        entry: process.env.VUE_APP_DATABI_ENTRY,
        container: '#appContainer',
        activeRule: process.env.VUE_APP_ROUTER_BASE + 'app/databi',
        props: { data: 'child子应用', mainAppRouter: history, store, router, actions }
    },
  }

第三步:配置子应用的全局状态actions。子应用中的全局状态必须要跟主应用中的全局状态变量属性名相同,比如主应用中全局状态变量为{project_id: “项目2”},则子应用中也需要保证在setGloabalState时,要改变该值,也要取相同的变量名。

先在子应用中配置一个空的actions实例,以便以后重新赋值从主应用中传递过来的actions。

function emptyAction(...args) {
    // 警告:提示当前使用的是空 Action
    console.warn("Current execute action is empty!");
}

// 我们首先设置一个用于通信的Actions类

class Actions {
    actions = {
        onGlobalStateChange: emptyAction,
        setGlobalState: emptyAction
    }
    constructor() {

    }
    // 默认值为空Action

    // 设置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

第四步:在mounted的生命周期里注入actions实例

子应用dataApi src/main.ts

/**
 * 微应用挂载钩子
 * @param props
 */
export async function mount(props: any) {
    if (props) {
        actions.setActions(props)
    }
    console.log(`[${appName}] app mounted11111${props}`);
    console.log('乾坤子应用容器加载完成,开始渲染 child')
    console.log(props.router)
    Vue.prototype.parentRouter = props.router;
    addEventBus(props);
    // await initAppBySelf();
    await initPermissionData()
    render(props);
}

2)主子应用互相传值

  • 子应用——>主应用
  • 主应用——>子应用
  • 子应用——>子应用

dataApi子应用

<template>
    <div class="view__container">
        测试应用间传值/跳转
        <div class="send__msg-box">
            <el-input placeholder="请输入内容" v-model="projectId" class="input-with-select">
                <el-button slot="append" icon="el-icon-search" @click="changeDataToMaster()"></el-button>
            </el-input>
        </div>
    </div>
</template>

<script>
import actions from '../../actions';

export default {
    name: 'OdeonTest',

    data() {
        return {
            projectId: ''
        };
    },

    mounted() {
        actions.onGlobalStateChange(state => {
            this.projectId = state.project_id;
        }, true); //onGlobalStateChange的第二个参数设置为true,则会立即触发一次观察者函数
    },

    methods: {
        changeDataToMaster() {
            //测试子应用修改全局状态project_id,父应用接收
            actions.setGlobalState({ project_id: this.projectId });
            window.history.pushState(null, '', `/odeon/v2/test-master-action`);
        },
    }
};
</script>

master主应用

<template>
    <div class="view__container">
        主应用:
        <div class="send__msg-box">
            <el-input placeholder="请输入内容" v-model="inputVal" class="input-with-select">
                <el-button slot="append" icon="el-icon-search" @click="changeDataToMicro"></el-button>
            </el-input>
        </div>
        <br />
        project_id的值为:{
   
   { projectId }}
    </div>
</template>

<script>
import actions from '@/actions';
export default {
    name: 'OdeonTest',
    data() {
        return {
            inputVal: '',
            projectId: ''
        };
    },

    mounted() {
        actions.onGlobalStateChange(({ project_id }) => {
            this.projectId = project_id;
            this.$store.commit('user/setUsername', '1111');
        }, true);
    },

    methods: {
        //主应用修改全局状态中的project_id值,在子应用中观察
        changeDataToMicro() {
            console.log(this.inputVal);
            actions.setGlobalState({ project_id: this.inputVal });
        
         this.$router.push({
                path: '/app/databi/layout/test'//跳转至dataApi子应用的xxx某页面
            })
        }
    },
};
</script>

webapp子应用(配置同dataApi)

(3)效果图

子应用-主应用


主应用-子应用


子应用——>子应用

二、props传值

  • 静态,无法监测到值变化
  • 在主应用 中注册子应用时,将定义好的msg通过props参数传递给子应用。
    //registerAppConfig.ts
    export const registerAppConfig = [
        {
            name: 'databi',
            entry: process.env.VUE_APP_DATABI_ENTRY,
            container: '#appContainer',
            activeRule: process.env.VUE_APP_ROUTER_BASE + 'app/databi',
            //将定义好的数据传递给子应用
            props: { data: 'child子应用', mainAppRouter: history, store, router, actions,msg:'12345' }
            
        },
  • 在 子应用的main.ts的mounted函数里将接收到的 props 参数内的函数挂在 vue 原型上方便使用,你也可以在其他导出的生命周期函数内得到 props 并按照你的设想去处理。
export async function mount(props: any) {
    if (props) {
        actions.setActions(props)
    }
    console.log('子应用挂载')

    console.log(`[${appName}] app mounted11111${props}`);
    console.log('乾坤子应用容器加载完成,开始渲染 child')
    console.log('msg:',props.msg)
      // 主应用传递的 方法 挂载原型上
    Vue.prototype.parentMsg = props.msg;
      // 主应用传递的 路由实例 挂载原型上
    Vue.prototype.parentRouter = props.router;
    addEventBus(props);
    // await initAppBySelf();
    await initPermissionData()
    render(props);
}

三 、主子应用共享vuex进行状态管理

具体见:浅析Vue项目如何基于Vuex进行qiankun微前端应用间通信方案实践:子应用无vuex共用主应用store的方案(子应用里如何保证主应用store在子应用的响应式)、子应用有独立store与主应用store分离共存的方案 - 古兰精 - 博客园 (转载)

猜你喜欢

转载自blog.csdn.net/qq_41885295/article/details/125843824