qiankun自定义数据通信方案
- 监听初始推送一次
- 合并多次变更
- 自动回收副作用
dataBus.js
/*
dataBus 单例
state
dispatch
forceDispatch
onListener @return offListner
offListner
initData
*/
import { reactive, watch } from 'vue'
import { tryOnBeforeUnmount } from '@vueuse/core'
let dataBus
function useTasks() {
const tasks = new Set()
function _runTasks() {
tasks.forEach((task) => task())
}
function runTask(task) {
tasks.add(task)
Promise.resolve().then(() => {
_runTasks()
tasks.clear()
})
}
return {
runTask
}
}
function createFactory(initialData = {}) {
const state = reactive(initialData)
const listeners = new Set()
const { runTask } = useTasks()
watch(
() => state,
() => {
runTask(_exe)
},
{ deep: true }
)
function _exe(newVal = state) {
listeners.forEach((listener) => listener(newVal))
}
function dispatch(newState) {
Object.assign(state, newState)
}
function forceDispatch(newState) {
dispatch(newState)
runTask(_exe)
}
function onListener(callback, initialPush) {
listeners.add(callback)
if (initialPush) runTask(_exe)
const clean = offListner.bind(this, callback)
tryOnBeforeUnmount(clean)
return clean
}
function offListner(callback) {
listeners.delete(callback)
}
dataBus = {
state,
dispatch,
forceDispatch,
onListener,
offListner
}
}
createFactory()
export function initData(initialData = {}) {
const data = dataBus.state
Object.keys(data).forEach(key => {
delete data[key];
});
Object.assign(data, initialData)
}
export default dataBus
MicroApp.vue
import dataBus from '@/utils/dataBus'
onMounted(() => {
if (window.registedMicroApps) return
window.registedMicroApps = true
registerMicroApps([
{
name: 'report',
entry: 'http://localhost:8080',
container: '.micro-app-container',
activeRule: '/child/report',
props: {
dataBus,
}
}
])
start({
sandbox: {
experimentalStyleIsolation: true
}
})
})
主应用使用例子1
import { initData } from '@/utils/dataBus'
initData({
collapse: false
})
主应用使用例子2
<template>
<div class="main-content">
state.collapse: {{ state.collapse }}
<el-radio-group v-model="state.collapse" style="margin-bottom: 20px" @change="handleSwichChange">
<el-radio-button :value="false">expand</el-radio-button>
<el-radio-button :value="true">collapse</el-radio-button>
</el-radio-group>
<RouterView />
</div>
</template>
<script setup>
import dataBus from '@/utils/dataBus'
const { state } = dataBus
</script>
微应用main.js
async function render(props = {}) {
const { container, dataBus } = props;
window.$dataBus = dataBus;
}
微应用使用例子1
created() {
if (window.$dataBus) {
const { onListener } = window.$dataBus;
onListener((data) => {
console.log("data变化:", data);
this.collapse = data.collapse;
}, true);
}
}
微应用使用例子2
const { state, forceDispatch, onListener } = window.$dataBus || {};
function toggle() {
if (!window.$dataBus) return;
forceDispatch({ collapse: !state.collapse });
}