• props
  • customEvent

    父子通信

    props

  • 当我们访问react16这个子应用的时候,不需要显示主应用的导航栏

  • 我们需要一个状态来控制导航栏的显示和隐藏
  • 子应用如何控制这个状态呢?

image.png

  • 首先回顾下之前学过的设计原则
    • 好莱坞原则 - 不用联系我,当我需要的时候会打电话给你
  • 我们可以通过以来注入的方式来使子应用控制主应用的状态

    • 依赖注入 - 主应用的显示隐藏,注入到子应用的内部,通过子应用的方法进行调用

      主应用设置要传递的数据

  • 主应用设置需要传递的数据 main/src/store/header.js ```javascript import { ref } from ‘vue’

// 是否显示头部 export const showHeader = ref(true)

export const changeHeader = (type) => { showHeader.value = type }

  1. - 为了后面可以把更多的数据注入到子应用使用,我们在主应用统一导出 main/src/store/index.js
  2. ```javascript
  3. // 头部数据
  4. export * as headerState from './header'
  • 在注册子应用列表时,绑定要传递给子应用的数据 main/src/store/leftNav.js ```javascript import * as appInfo from ‘../store’

export const navList = [ { name: ‘react15’,// 唯一id entry: ‘//localhost:9002/‘, // 子应用入口地址 loading, container: ‘#micro-container’, // 子应用渲染容器 activeRule: ‘/react15’, // 激活状态 appInfo, // 绑定要传给子应用的数据、方法等等 }, ]

<a name="NM0rl"></a>
### 微前端框架mout时将主应用信息传递给子应用

- 在微前端框架中,触发mount生命周期时,传递给子应用 main/micro/lifeCycle.js/index.js
```javascript
// 微前端的生命周期 - mounted
export const mounted = async (app) => {
  app && app.mount && app.mount({
    appInfo: app.appInfo,
    entry: app.entry
  })
  await runMainLifecycle('mounted')
}

子应用在mount时接收主应用信息

  • 子应用在mount生命周期可以接收到我们注入的数据、方法

    export async function mount(app) {
    console.log('app', app)
    console.log('react mount')
    render()
    setTimeout(() => {
      // 调用隐藏头部方法 false 隐藏  true 显示
      app.appInfo.headerState.changeHeader(false)
    }, 3000)
    }
    
  • 我们也可以将主应用传递过来的数据,进行存储,这样子应用需要调用的地方就可以直接调用到了

    import { setMain } from './src/utils/global'
    export async function mount(app) {
    console.log('app', app)
    setMain(app)
    console.log('react mount')
    render()
    }
    
  • react16/src/utils/global.js ```javascript export let main = {}

export const getMain = () => { return main }

export const setMain = (data) => { main = data }


- 比如我们要在子应用登陆页面,隐藏主应用头部 react16/src/pages/login/index.jsx
```javascript
import { getMain } from '../../utils/global'

const Login = () => {

  useEffect(() => {
    const main = getMain()
    if (!main?.appInfo) {
      return
    }
    // 登录页面隐藏头部底部
    main.appInfo.footerState.changeFooter(false)
    main.appInfo.headerState.changeHeader(false)
    main.appInfo.crumbsState.setCrumbs([])
  }, [])

  return (
    <div className="login">
      <img className="loginBackground" src={`${globalConfig.baseUrl}/login-background.png`} />
      <LoginPanel />
    </div>
  )
}

customEvent

通过自定义事件监听,来实现父子组件通信

  • main/micro/customEvent/index.js

    export class Custom {
    // 事件监听
    on(name, cb) {
      window.addEventListener(name, (e) => {
        cb(e.detail)
      })
    }
    // 事件触发
    emit(name, data) {
      const event = new CustomEvent(name, {
        detail: data
      })
      window.dispatchEvent(event)
    }
    }
    
  • 主应用创建自定义监听实例 main/micro/start.js ```javascript import { Custom } from ‘./customEvent’ const custom = new Custom()

window.custom = custom


- 主应用监听自定义事件消息
```javascript
custom.on('test', (data) => {
  console.log(data);
})
  • 子应用发送自定义消息

    window.custom.emit('test', {
    a: 1
    })
    

    子应用间通讯

  • 子应用间通信也可以是使用上面两种方式

  • props
    • 子应用1->主应用->主应用2
  • customEvent

    customEvent

  • 假如我们第一个子应用显示的是vue3,切换第二个子应用是vue2

  • 当我们vue2向vue3发送数据,我们可以正常监听 ```javascript // vue3 window.custom.on(‘test1’, (data) => { console.log(data); })

// vue2 window.custom.emit(‘test1’, { a: 1 })


- 当我们想让vue3给vue2发送数据,就需要注意下调用顺序以及,监听顺序
- 先监听,后发送
- 我们先显示的是vue3,vue3给vue2发送数据,vue2还没有监听,所以收不到数据
- 我们可以让vue3监听vue2,当切换到vue2时,监听vue3的事件,发送消息告诉vue3我开始监听了,可以发送数据了,此时vue3发送数据,vue2就可以监听到了
```javascript
// vue3
window.custom.on('test1', () => {
    // console.log(data);
  window.custom.emit('test2', {
    b: 2
  })
})


// vue2 
export async function mount() {
  window.custom.on('test2', data => {
    console.log(data, '=====vue2监听vue3数据');
  })
  // 通知vue3我可以接收数据了
  window.custom.emit('test1', {
    a: 1
  })
  console.log('渲染成功');
  render()
}