qiankun通信方式及子应用引用百度地图的修改

1,960 阅读2分钟

基座如何修改

1.安装qiankunyarn add qiankun
2.注册微应用并启动

// main.js
import { registerMicroApps, start } from 'qiankun';
registerMicroApps([
    {
        name: 'child',
        entry: '//localhost:9000',
        container: '#container',
        activeRule: '/sub',
    }
]);
start()

子应用如何修改

具体代码略,可参考官网qiankun
概要如下:

1.src目录下新增public-path.js,并在main.js中引入
2.main.js中抛出3个方法 bootstrap mount unmount
3.改造main中createapp的方式
4.打包配置修改(vue.config.js)

基座与子应用如何通信

基座与子应用的通讯只是用了APIinitGlobalState
initGlobalState返回一个MicroAppStateActions对象,它有三个属性:

  • onGlobalStateChange: (callback: OnGlobalStateChangeCallback, fireImmediately?: boolean) => void, 在当前应用监听全局状态,有变更触发 callback,fireImmediately = true 立即触发 callback
  • setGlobalState: (state: Record<string, any>) => boolean, 按一级属性设置全局状态,微应用中只能修改已存在的一级属性
  • offGlobalStateChange: () => boolean,移除当前应用的状态监听,微应用 umount 时会默认调用

父应用如何做

import { initGlobalState } from 'qiankun';
const state = {
    baiduinit: window,
    abc: 456
}
// 初始化通信池
const actions = initGlobalState(state);
// 监听通讯池的变化
actions.onGlobalStateChange((state, prev) => {
    // state: 变更后的状态; prev 变更前的状态
    console.log(state, prev);
});

子应用如何做

1.创建action.js

// /src/qiankun/action.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() {
        return this.actions.onGlobalStateChange(...arguments);
    }

    /**
     * 映射
     */
    setGlobalState() {
        return this.actions.setGlobalState(...arguments);
    }
}

const actions = new Actions();
export default actions;

2.在main.js mount方法中接收父应用的传值props

import action from './qiankun/action'
export async function mount(props) {
    console.log('[vue] props from main framework', props);
    action.setActions(props)
    render(props);
}

3.在需要接收父应用传入的参数的地方引用action.js

import action from '@/qiankun/action'
export default {
    name: 'Home',
    mounted() {
        // 接收state
        action.onGlobalStateChange((state) => {
            console.log(state)
        }, true);
    },
    methods:{
        changeValue(){
            // 修改state
            action.setGlobalState({abc:789})
        }
    }
}

子应用可以修改通讯池,修改完会被基座监听到。

子应用引用了百度地图

子应用引用了第三方js库,在乾坤环境中会有跨域的问题,因为乾坤会把子应用的静态资源放到沙箱中,这样第三方js经过编译就会出现问题。解决方式是在基座中start方法中设置excludeAssetFilter,使qiankun不处理这部分js

// main.js
import { registerMicroApps, start } from 'qiankun';
start(
    {
        excludeAssetFilter: (urls) => {
            const whiteList = []
            const whiteWords = ['baidu'] // 异步加载百度地图白名单
            if (whiteList.includes(urls)) return true
            return whiteWords.some(w => urls.includes(w))
        }
    }
);

百度地图的初始化需要把init挂到window上,而在qiankun环境中window不是window了,我想到的办法是把window通过传参传给子应用,处理如下:

// bmap.vue
import action from '@/qiankun/action'
export default {
    mounted() {
        // 创建了script标签callback走的方法
        window.baiduinit = ()=>{
            this.initBaiduMap(116.404, 39.915)
        }
        // 如果在乾坤环境window不是window
        if(window.__POWERED_BY_QIANKUN__){
            action.onGlobalStateChange((state) => {
                state.baiduinit.baiduinit = ()=>{
                    this.initBaiduMap(116.404, 39.915)
                }
            }, true);
        }
        // 检测到已经创建了标签走的方法
        this.createMap().then(()=>{
            this.initBaiduMap(116.404, 39.915)
        })
    },
    methods: {
        // 创建script标签
        createMap(){
            return new Promise((resolve,reject)=>{
                const map = document.getElementById('baidumap');
                if(map){
                    resolve()
                    return
                }
                console.log('create baidu map')
                let script = document.createElement('script');
                script.id = 'baidumap';
                script.type = 'text/javascript';
                script.src = `https://api.map.baidu.com/api?v=3.0&ak=你的ak&callback=baiduinit`;
                document.body.appendChild(script);
            })
        }
        ...

源码

gitee.com/clausliang/…