0


微前端:qiankun的五种通信方式

背景

今天盘点一下 qiankun 父子应用的通信方式都有哪些,我发现了 5 种。

1、localStorage/sessionStorage
2、通过路由参数共享
3、官方提供的 props
4、官方提供的 actions
5、使用vuex或redux管理状态,通过shared分享

接下来我们一个一个进行说明

1、localStorage/sessionStorage

有人说这个方案必须主应用和子应用是同一个域名下。其实不是的,子应用使用不同的域名也是可以的,因为在 qiankun 中,主应用是通过 fetch 来拉取子应用的模板,然后渲染在主应用的 dom 上的,说白了还是运行在主应用上,所以还是运行在同一个域名上,也就是主应用的域名。

父传子

主应用 main.js

localStorage.setItem('token','123')
console.log('在main中设置了token')

子应用app1 main.js

const token = localStorage.getItem('token')
console.log('app1中打印token:', token)

我们可以看到,从主应用的首页跳到微应用 app1 的首页,分别打印了这两项,说明是可以通过 localstorage 通信的。
在这里插入图片描述

子传父

同理app1修改token,main也可以看到,这里就不再赘述

2、通过路由参数共享

这个也很好理解,因为只有一个 url,不过子应用还是主应用给 url 上拼接一些参数,那么父子应用都可以通过 route 来获取到。

父传子

这里我没有找到父传子的场景

子传父

主应用跳到子应用,子应用内部路由跳转携带参数,父应用通过路由守卫可以拿到路由上的参数。
在这里插入图片描述

从 main 首页跳到 app1 首页,app1 首页点击列表跳到了 app1 的详情页,可以看到详情页的 url 上分别带了两个参数,而路由跳转的时候触发了 main 的路由守卫,捕获到了这个路由。

可以看到这里的 meta 和 name 是空的,但是我子应用明明有设置啊,这是怎么回事?

其实捕获到的路由对象是主应用的,而不是子应用的,这里能获取到这两个参数,完全是因为路由守卫获取的时候只关心 url 的 ? 后面的参数,所以这里碰巧共享了。

如果父应用想完整的获取子应用的路由怎么获取呢?
只能通过其他传值方式将子应用的路由对象传给父应用了。
把父应用的路由实例传给子应用,也是没用的,大家可以不用尝试了。

3、官方提供的 props

上一篇文章 微前端:qiankun的两种运作模式 介绍了qiankun 的两种运作模式,而这两种模式都提供了一个参数 props。

父传子

我们以一个例子来示范一下,这个例子是父应用把父路由的实例传递给子应用。

父应用:

import{
  registerMicroApps,
  start,}from"qiankun";import router from'@/router'const apps =[{name:"App1MicroApp",entry:'//localhost:9001',container:"#app1",activeRule:"/app1",props:{parentRouter: router
    }}];registerMicroApps(apps);start();

子应用:

let instance =nulllet router =nullfunctionrender(props){
  router =newVueRouter({base: window.__POWERED_BY_QIANKUN__ ?'/app1':'',mode:'history',routes: routes
  })
  instance =newVue({
    router,
    store,// 挂载在根节点上data(){return{parentRouter: props.parentRouter,}},render:(h)=>h(App)}).$mount('#app')}exportasyncfunctionmount(props){render(props);}// 在子应用中使用就可以访问到这个parentRouter了this.$root.parentRouter

子传父

同理,传进来一个函数或者对象等,子应用操作这个对象就是改变的父应用的状态。
类似 react 的通信方式。

4、官方提供的 actions

就一个 API initGlobalState(state)
参数:传入你维护的一个 state,类似 store 中的 state
返回:action 实例,并挂载了三个函数
1、

onGlobalStateChange: (callback: OnGlobalStateChangeCallback, fireImmediately?: boolean) => void

, 在当前应用监听全局状态,有变更触发 callback,fireImmediately = true 立即触发 callback

2、

setGlobalState: (state: Record<string, any>) => boolean

, 可以在应用中任何地方调用来修改全局状态,子应用想使用的话可以通过 props 把 action 传给子应用使用

3、

offGlobalStateChange: () => boolean

,移除当前应用的状态监听,微应用 umount 时会默认调用

父传子

主应用:
src/micro/actions.ts

import{ initGlobalState, MicroAppStateActions }from'qiankun';const state ={num:1};// 初始化 stateconstactions: MicroAppStateActions =initGlobalState(state);

actions.onGlobalStateChange((state, prev)=>{// state: 变更后的状态; prev 变更前的状态
  console.log('主应用检测到state变更:', state, prev);});// 你还可以定义一个获取state的方法下发到子应用
actions.getGlobalState=function(){return state
}exportdefault actions;

当然,父应用也可以自己通过这个 actions 来调用 setGlobalState 函数改变全局状态 state

src/micro/index.js

import{
  registerMicroApps,
  start,}from"qiankun";import actions from'./actions'const apps =[{name:"App1MicroApp",entry:'//localhost:9001',container:"#app1",activeRule:"/app1",props:{parentActions: actions
    }}];registerMicroApps(apps);start();

这样就把这个 actions 传给了子应用。

子应用:

let instance =nulllet router =nullfunctionrender(props){
  router =newVueRouter({base: window.__POWERED_BY_QIANKUN__ ?'/app1':'',mode:'history',routes: routes
  })
  instance =newVue({
    router,
    store,// 挂载在根节点上data(){return{parentActions: props.parentActions,}},render:(h)=>h(App)}).$mount('#app')}exportasyncfunctionmount(props){render(props);}// 在子应用中使用就可以访问到这个parentActions了this.$root.parentActions.setGlobalState({num:2})// 调用挂载在 actions 上的自定义方法,获取当前的全局 statethis.$root.parentActions.getGlobalState()

我在子应用的 mounted 中把全局 state 的 num 设置了 2,就是如下效果。
在这里插入图片描述

子传父

上面例子其实已经都包括了。再总结一下就是:

父传子就是父应用通过 props 把 parentActions 传给子应用,子传父就是子应用接受到 parentActions 可以来改变父应用的状态。

5、shared 方案

这个方案我大概描述一下,就不写代码细讲了,因为和上面的方案很像。

就是父应用通过 vuex 或者 redux 正常使用维护一个 state,然后创建一个 shared 实例,这个实例提供对 state 的增删改查,然后通过 props 把这个 shared 实例传给子应用,子应用使用就行。

主应用:
这个 shared 实例大概就长这样:

// micro-app-main/src/shared/index.tsimport store from"./store";classShared{/**
   * 获取 Token
   */publicgetToken(): string {const state = store.getState();return state.token ||"";}/**
   * 设置 Token
   */publicsetToken(token: string):void{// 将 token 的值记录在 store 中
    store.dispatch({type:"SET_TOKEN",payload: token
    });}}const shared =newShared();exportdefault shared;

同样的传入方式
src/micro/index.js

import{
  registerMicroApps,
  start,}from"qiankun";import shared from'./shared'const apps =[{name:"App1MicroApp",entry:'//localhost:9001',container:"#app1",activeRule:"/app1",props:{parentShared: shared
    }}];registerMicroApps(apps);start();

想要了解具体可以看这篇文章:
https://cloud.tencent.com/developer/article/1770605

总结

  • 类似设置全局共享 token 就适合方案1
  • 每个页面要设置不同的title,可以用方案2在 url 上带上一个 title,这样父子应用都能监听到
  • 方案3则适合一些复杂一点的数据交互
  • 一般到方案3,就可以了,如果需要方案4了,就说明应用交流太频繁了,考虑是不是你们的应用拆分的有问题
标签: 前端 javascript html5

本文转载自: https://blog.csdn.net/weixin_43972437/article/details/128154083
版权归原作者 Lvan的前端笔记 所有, 如有侵权,请联系我们删除。

“微前端:qiankun的五种通信方式”的评论:

还没有评论