无界微前端:
关键词:
sync: 浏览器刷新、前进、后退子应用路由状态也都不会丢失(为true时,url后面会拼接路由参数)
exec: 预执行指的是在应用空闲的时候将子应用提前渲染出来,可以进一步提升子应用打开时间,只需要在preloadApp中将 exec 设置为true即可
alive: true子应用保活
当子应用设置为保活模式,切换子应用后仍然可以保持子应用的状态和路由不会丢失。
运行模式
保活模式
在保活模式下,子应用只会进行一次渲染,页面发生切换时承载子应用 dom 的 webcomponent 会保留在内存中,当子应用重新激活时无界会将内存中的 webcomponent 重新挂载到容器上。实例不销毁。
Cors机制:
跨源 HTTP 请求的一个例子:运行在 https://domain-a.com
的 JavaScript 代码使用 XMLHttpRequest 来发起一个到 https://domain-b.com/data.json
的请求。
除非响应报文包含了正确 CORS 响应头。
切换页面后再进子应用页面不走创建createApp,从内存取值,类似与keep-alive标签作用。
再次进入页面生命周期走activated 、退出页面deactivated。
切换页面后再进子应用不走下面创建:
主应用承载子应用实例的dom不重新创建:
再次进入页面:
单例模式
子应用的 alive 为 false, 且子应用进行了生命周期改造时进入单例模式。
子应用页面如果切走,会调用 window.WUJIE_UNMOUNT 销毁子应用当前实例,子应用页面如果切换回来,会调用 window.WUJIE_MOUNT 渲染子应用新的子应用实例
生命周期:
如果子应用没有做生命周期的改造,那么 beforeMount、afterMount、beforeUnmount、afterUnmount 这四个生命周期将不会调用
子应用生命周期改造:
主应用生命周期:(主应用生命周期跟模式没有关系)
主应用承载子应用的实例保留
切换页面后
重建模式
子应既没有设置为保活模式,也没有进行生命周期的改造则进入了重建模式,每次页面切换不仅会销毁承载子应用 dom 的 webcomponent,还会销毁承载子应用 js 的 iframe,相应的 wujie 实例和子应用实例都会被销毁
通信:
无界提供多种通信方式:
1.window.parent 直接通信(子取父值):
- 子应用 js 在和主应用同域的 iframe 内运行,所以 window.parent 可以直接拿到主应用的 window 对象来进行通信
主应用:
子应用: let globalSunValue = window.parent.globalMainValue // 取主应用全局变量
2.props 数据注入
- 主应用可以向子应用注入 props 对象,里面可以注入数据和方法供子应用调用
主应用:
子应用:
执行父应用通过props传递的方法
主应用:
子应用:
3. EventBus 通信机制:
import wujieVue from 'wujie-vue3'
wujieVue.bus.$emit('microEmit', '主应用测试data')
wujieVue.bus.$on('microEmit', (val) => {
this.value = val
})
注意:$emit必须在$on监听启用之后再传,子应用才能收到值
- 内置的 EventBus 去中心化通信方案可以让应用之间方便的直接通信
生命周期:
无界提供完善的生命周期钩子供主应用调用:
- beforeLoad:子应用开始加载静态资源前触发
- beforeMount:子应用渲染前触发 (生命周期改造专用)
- afterMount:子应用渲染后触发(生命周期改造专用)
- beforeUnmount:子应用卸载前触发(生命周期改造专用)
- afterUnmount:子应用卸载后触发(生命周期改造专用)
- activated:子应用进入后触发(保活模式专用)
- deactivated:子应用离开后触发(保活模式专用)
- 主应用:
- package.json
"wujie-vue3": "^1.0.8",
- Main.js
- 预加载和默认设置非必须
import WujieVue from 'wujie-vue3'
// eslint-disable-next-line no-unused-vars
const { setupApp, preloadApp } = WujieVue
// 非必须函数
setupApp({
alive: true,
exec: true,
name: 'ceshi', // 这里这个名称要和展示子应用页面设置的名称一样哦!!!!
url: hostMap(ENV_DOMAIN_MT_MAP[process.env.NODE_ENV]), // 子应用的域名链接
})
// 预加载非必须函数
preloadApp({
name: 'ceshi', // 这里这个名称要和展示子应用页面设置的名称一样哦!!!!
url: hostMap(ENV_DOMAIN_MT_MAP[process.env.NODE_ENV]), // 子应用的域名链接
})
下面引入是必须的
问题:
- 子应用引用的相对路径静态资源会挂在主应用上
- 主应用调用子应用接口,cors机制原因需要服务端的response的header参数与request的请求头保持一致,或者不必要的参数不传。
- 子应用的弹框只能在子应用页面用。
- 路由通过 window.encodeURIComponent 编码后挂载在主应用 url 的查询参数上,其中 key 值为子应用的 name。
wujie+vue3+ts示例代码
<!-- eslint-disable vue/require-prop-types -->
<template>
<div id="wujiePage">
<!-- //组件穿透传值 data值 method方法propsMethod -->
<WujieVue
width="100%"
height="100%"
:sync="true"
name="form"
:props="{ data: propsData, method: { propsMethod } }"
:url="mtUrl"
/>
</div>
</template>
<script lang="ts" setup>
import wujieVue from 'wujie-vue3';
import { reactive, ref, defineProps, defineEmits, defineExpose } from 'vue';
import { ENV_DOMAIN_MT_MAP } from '/@/utils/wujie/sub-app';
// 示例代码/
// window.globalMainValue = '我是无界主应用全局变量';
/* token:表单项目token
tempId:模板ID(int类型)
projectId:项目ID(int类型)
isEdit:模板是否可编辑(布尔型,默认true)
isShow:模板提交按钮是否显示(布尔型,默认true)
data:模板数据,点击模板提交按钮或者haveData参数为true时产生
haveData:模板是否需要返回数据(布尔型,加载模板时传false,需要返回数据时传true)*/
const props = defineProps({
pdata: {} as any
});
const propsData = reactive({
tempId: props.pdata.tempId, // 575 576 577 578
projectId: props.pdata.projectId,
isEdit: props.pdata.isEdit,
isShow: props.pdata.isShow,
data: props.pdata.data,
haveData: props.pdata.haveData,
wujieIsHwork: !!window.__IS_HWORK_QIANKUN__
});
let mtUrl: any = ref('');
const emits = defineEmits(['getData']);
function loadMounted() {
// 主应用监听子应用传值
wujieVue.bus.$on('microEmit', (val: any) => {
emits('getData', val);
});
mtUrl = `${ENV_DOMAIN_MT_MAP[process.env.NODE_ENV]}/`;
// 示例代码--不能在主应用mounted里面使用
// wujieVue.bus.$emit('microEmit', { tempId: 256, projectId: 900003346, isEdit: true, isShow: true, data: '', haveData: false})
}
function propsMethod() {
//主应用取值
// console.log(window.document.querySelector('iframe[name=form]').contentWindow?.globalMicroValue);
}
function setData(tempId, data, haveData) {
if (tempId) propsData.tempId = tempId;
if (data || data === '') propsData.data = data;
propsData.haveData = haveData;
wujieVue.bus.$emit('microEmit', propsData);
}
function setDataAll(propsData) {
wujieVue.bus.$emit('microEmit', propsData);
}
function destroyBus() {
wujieVue.bus.$clear();
}
defineExpose({
setData,
setDataAll,
destroyBus
});
loadMounted();
//
</script>
<style lang="less" scoped>
.wujiePage {
margin: 10px 10px 10px 10px;
}
</style>