- 首先回顾下之前学过的设计原则
- 好莱坞原则 - 不用联系我,当我需要的时候会打电话给你
我们可以通过以来注入的方式来使子应用控制主应用的状态
主应用设置需要传递的数据 main/src/store/header.js ```javascript import { ref } from ‘vue’
// 是否显示头部 export const showHeader = ref(true)
export const changeHeader = (type) => { showHeader.value = type }
- 为了后面可以把更多的数据注入到子应用使用,我们在主应用统一导出 main/src/store/index.js
```javascript
// 头部数据
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
假如我们第一个子应用显示的是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()
}