子应用主应用间如何通信
qiankun官方提供了actions通信,qiankun内部使用initGlobalState(state)定义全局状态,该方法执行后返回一个MicroAppStateActions实例,实例中包含三个方法,分别是onGlobalStateChange、setGlobalState、offGlobalStateChange。
MicroAppStateActions
onGlobalStateChange: (callback: OnGlobalStateChangeCallback, fireImmediately?: boolean) => void //在当前应用监听全局状态,有变更触发 callback,fireImmediately = true 立即触发 callback
setGlobalState: (state: Record<string, any>) => boolean, //按一级属性设置全局状态,微应用中只能修改已存在的一级属性(就是用来修改全局状态的
offGlobalStateChange: () => boolean //移除当前应用的状态监听,微应用 umount 时会默认调用
- 1
- 2
- 3
- 4
实战:父子应用之间相互通信:
==第一步:==首先需要在父应用中使用initGlobalState设置全局状态actions并导出供其他组件使用。
src/action.js:
// 此action文件为定义微应用之间全局状态
// 引入qiankun的应用间通信方法initGlobalState
import { initGlobalState, MicroAppStateActions } from 'qiankun'
const initialState = {
// 这里可以写初始化数据
}
const actions = initGlobalState(initialState) //初始化state
// 监听actions全局公共状态数据的变化
actions.onGlobalStateChange((state, prevState) => {
console.log("主应用变更前:", prevState);
console.log("主应用变更后:", state);
this.$store.commit("setProject", state) //将获取的最新的公共状态保存到vuex中
})
export default actions
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
==第二步:==然后在main.js中引入actions实例并在注册子应用时通过props传递全局状态actions:
main.js
// 注册的应用列表
const apps = [
// 子应用vue应用
{
name: 'vueApp', //应用名字
// 默认请求的url,并解析里面的js,因为此时父应用请求了子应用里面的资源,所以子应用必须支持跨域
entry: "http://localhost:8001",
//容器名,子应用挂载到哪个元素
container: "#container",
//路由匹配激活规则,当路由匹配到activeRule时,就会请求获取entry资源,然后渲染到container容器中
activeRule: '/vue',
// 通过props实现通信传递值
props: { actions, msg: "w" } //向子应用传递创建的全局状态
}
]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
第三步:
主应用中的组件要修改全局状态actions,就在此组件中引入actions实例
Home.vue:
<template>
<div class="home">
<button @click="handle1">点击向子应用发送消息</button>
<button @click="handle2">点击向子应用发送消息</button>
<p>当前显示的项目:{{ project }}</p>
</div>
</template>
<script>
import HelloWorld from "@/components/HelloWorld.vue"; //引入的HelloWorld组件
import actions from "../action";
export default {
name: "Home",
data() {
return {
mes1: {
project_id: "项目1",
},
mes2: {
project_id: "项目2",
},
};
},
computed: {
project() {
return this.$store.state.project_id;
},
},
mounted() {
// 需要在mounted钩子函数中注册qiankun的观察者函数
// 注册一个观察者函数
// 一旦修改actions的内容就会触发这个onGlobalStateChange监听函数
actions.onGlobalStateChange((state, prevState) => {
// state为变更后的状态,prevState为变更前的状态
console.log("主应用观察者,改变前的state为:", prevState);
console.log("主应用观察者,改变后的state为:", state);
});
},
methods: {
handle1() {
actions.setGlobalState(this.mes1); //修改全局的actions
this.$router.push("/vue"); //跳转到vue子应用中
},
handle2() {
actions.setGlobalState(this.mes2); //修改全局的actions
this.$router.push("/vue"); //跳转到vue子应用中
},
},
components: {
HelloWorld, //注册组件
},
};
</script>
- 1
- 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
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
第四步:配置子应用的全局状态Actions,子应用中的全局状态必须要跟主应用中的全局状态变量属性名相同,比如主应用中全局状态变量为{project_id: “项目2”},则子应用中也需要保证在setGloabalState时也需要设定相同的变量名。
先在子应用中配置一个空的actions实例为以后重新赋值从主应用中传递过来的actions:
actions.js
function emptyAction() {
// 警告:提示当前使用的是空 Action
console.warn("Current execute action is empty!");
}
// 我们首先设置一个用于通信的Actions类
class Actions {
actions = {
onGlobalStateChange: emptyAction,
setGlobalState: emptyAction
}
constructor() {
<span class="token punctuation">}</span>
<span class="token comment">// 默认值为空Action</span>
<span class="token comment">// 设置actions</span>
<span class="token function">setActions</span><span class="token punctuation">(</span><span class="token parameter">actions</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token keyword">this</span><span class="token punctuation">.</span>actions <span class="token operator">=</span> actions
<span class="token punctuation">}</span>
<span class="token comment">// 映射</span>
<span class="token function">onGlobalStateChange</span><span class="token punctuation">(</span><span class="token parameter"><span class="token operator">...</span>args</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>actions<span class="token punctuation">.</span><span class="token function">onGlobalStateChange</span><span class="token punctuation">(</span><span class="token operator">...</span>args<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token comment">// 映射</span>
<span class="token function">setGlobalState</span><span class="token punctuation">(</span><span class="token parameter"><span class="token operator">...</span>args</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>actions<span class="token punctuation">.</span><span class="token function">setGlobalState</span><span class="token punctuation">(</span><span class="token operator">...</span>args<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
}
const actions = new Actions()
export default actions
- 1
- 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
然后在mounted的生命周期里注入actions实例:
main.js
function render(props) {
if (props) {
actions.setActions(props)
}
const { container } = props
// 渲染的时候赋值
instance = new Vue({
router,
store,
render: h => h(App)
}).$mount(container ? container.querySelector("#app") : '#app') //这里是挂载到自己的html中,基座会拿到这个挂载后的html,将其插入进去
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
子应用向主应用发送数据(子应用中修改数据,可以在主应用中监听到)
子应用的组件Home.vue:
<template>
<div class="home">
<button @click="handle">快点我向父应用发送数据</button>
<p>{{ msg }}</p>
<img alt="Vue logo" src="../assets/logo.png" />
<HelloWorld msg="Welcome to Your Vue.js App" />
</div>
</template>
<script>
// @ is an alias to /src
import HelloWorld from "@/components/HelloWorld.vue";
import actions from "../actions";
export default {
name: "Home",
data() {
return {
msg: "2",
};
},
mounted() {
// console.log("cccc");
// console.log(actions);
actions.onGlobalStateChange((state) => {
console.log("我是子应用,我检测到数据了:", state);
this.msg = state;
}, true); //onGlobalStateChange的第二个参数设置为true,则会立即触发一次观察者函数
},
methods: {
handle() {
actions.setGlobalState({ project_id: "项目520" });
},
},
components: {
HelloWorld,
},
};
</script>
- 1
- 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
- 39
- 40