vue3项目作为父应用
// 下载wujie
// npm install wujie-vue3
// 引入
import WujieVue from 'wujie-vue3'
// ...
// 使用插件
app.use(WujieVue)
const { setupApp, preloadApp } = WujieVue
// 注册子应用
setupApp({
name: 'react-app', // 子应用名称
url: 'http://127.0.0.1:3000/', // 子应用项目地址
alive: true, // 是否开启保活模式
})
setupApp({
name: 'vue-app',
url: 'http://127.0.0.1:3001/',
alive: true
})
无界的三种运行模式
1.保活模式
设置alive为true,子应用只会被渲染一次,内部的数据和路由的状态不会随着页面切换而丢失。
2.单例模式
子应用的alive为false且进行了生命周期改造时进入单例模式。在单例式下,改变 url 子应用的路由会发生跳转到对应路由。所有的子应用共享一个Wujie实例。
3.重建模式
子应用既没有设置为保活模式,也没有进行生命周期的改造则进入了重建模式。每次切换子应用时都会销毁原本的应用创建新的应用。
组件内使用无界
<WujieVue
width="100%"
height="100%"
:name="vue-app"
></WujieVue>
无界的应用通信系统
1.使用props
主应用注入数据
<WujieVue
width="100%"
height="100%"
:name="vue-app"
:props="{name: 'wujie', age: 18}"
></WujieVue>
子应用接收
console.log('vue',window.$wujie.props) // {name: 'wujie', age: 18}
2.window通信
父应用传输数据
window.document.querySelector("iframe[name=wujie-vue]").contentWindow.peiqi
子应用接收数据
console.log('vue', window.parent) // {peiqi: 'hello word'}
3.使用eventBus
父应用使用方式:
// 引入bus
import WujieVue from "wujie-vue";
const { bus } = WujieVue;
// 主应用监听事件
bus.$on("事件名字", function (arg1, arg2, ...) {});
// 主应用发送事件
bus.$emit("事件名字", arg1, arg2, ...);
// 主应用取消事件监听
bus.$off("事件名字", function (arg1, arg2, ...) {});
子应用使用:
// 子应用监听事件
window.$wujie?.bus.$on("事件名字", function (arg1, arg2, ...) {});
// 子应用发送事件
window.$wujie?.bus.$emit("事件名字", arg1, arg2, ...);
// 子应用取消事件监听
window.$wujie?.bus.$off("事件名字", function (arg1, arg2, ...) {});
实现一个WujieVue组件,接受相关属性(只实现了部分属性,其它的大同小异)
src/index.ts文件
// 引入wujie和vue
import { defineComponent, h, getCurrentInstance, onMounted, watch, onBeforeUnmount } from 'vue'
import type { PropType } from 'vue'
import { Props } from './type'
import { startApp, bus } from 'wujie'
// 定义组件
const wujie = defineComponent({
props: {
width: { type: String, default: "" },
height: { type: String, default: "" },
name: { type: String, default: "", required: true },
loading: { type: HTMLElement, default: undefined },
url: { type: String, default: "", required: true },
sync: { type: Boolean, default: undefined },
prefix: { type: Object, default: undefined },
alive: { type: Boolean, default: undefined },
props: { type: Object, default: undefined },
attrs: { type: Object, default: undefined },
replace: { type: Function as PropType<Props['replace']>, default: undefined },
fetch: { type: Function as PropType<Props['fetch']>, default: undefined },
fiber: { type: Boolean, default: undefined },
degrade: { type: Boolean, default: undefined },
plugins: { type: Array as PropType<Props['plugins']>, default: null },
beforeLoad: { type: Function as PropType<Props['beforeLoad']>, default: null },
beforeMount: { type: Function as PropType<Props['beforeMount']>, default: null },
afterMount: { type: Function as PropType<Props['afterMount']>, default: null },
beforeUnmount: { type: Function as PropType<Props['beforeUnmount']>, default: null },
afterUnmount: { type: Function as PropType<Props['afterUnmount']>, default: null },
activated: { type: Function as PropType<Props['activated']>, default: null },
deactivated: { type: Function as PropType<Props['deactivated']>, default: null },
},
setup(props, { emit }) {
const instance = getCurrentInstance();
const init = () => {
// 微前端初始化方法
startApp({
name: props.name,
url: props.url,
el: instance?.refs.wujie as HTMLElement,
loading: props.loading,
alive: props.alive,
fetch: props.fetch,
props: props.props,
attrs: props.attrs,
replace: props.replace,
sync: props.sync,
prefix: props.prefix,
fiber: props.fiber,
degrade: props.degrade,
plugins: props.plugins,
beforeLoad: props.beforeLoad,
beforeMount: props.beforeMount,
afterMount: props.afterMount,
beforeUnmount: props.beforeUnmount,
afterUnmount: props.afterUnmount,
activated: props.activated,
deactivated: props.deactivated,
})
}
watch([props.name, props.url], () => {
init()
})
const handleEmit = (event: string, ...args: any[]) => {
emit(event, ...args)
}
onMounted(() => {
bus.$onAll(handleEmit)
init()
})
onBeforeUnmount(() => {
bus.$offAll(handleEmit)
})
return () => h('div', {
style: {
height: props.height,
width: props.width,
},
ref: 'wujie'
})
}
})
// app.use()时会执行wujie的install方法注册全局组件
wujie.install = (app: any) => {
app.component('WujieVue', wujie)
}
export default wujie
src/type.ts
import type { plugin } from 'wujie'
type lifecycle = (appWindow: Window) => any;
interface Props {
/** 唯一性用户必须保证 */
name: string;
/** 需要渲染的url */
url: string;
/** 需要渲染的html, 如果用户已有则无需从url请求 */
html?: string;
/** 渲染的容器 */
loading?: HTMLElement;
/** 路由同步开关, false刷新无效,但是前进后退依然有效 */
sync?: boolean;
/** 子应用短路径替换,路由同步时生效 */
prefix?: { [key: string]: string };
/** 子应用保活模式,state不会丢失 */
alive?: boolean;
/** 注入给子应用的数据 */
props?: { [key: string]: any };
/** js采用fiber模式执行 */
fiber?: boolean;
/** 子应用采用降级iframe方案 */
degrade?: boolean;
/** 自定义运行iframe的属性 */
attrs?: { [key: string]: any };
/** 自定义降级渲染iframe的属性 */
degradeAttrs?: { [key: string]: any };
/** 代码替换钩子 */
replace?: (codeText: string) => string;
/** 自定义fetch,资源和接口 */
fetch?: (input: RequestInfo, init?: RequestInit) => Promise<Response>;
/** 子应插件 */
plugins: Array<plugin>;
/** 子应用生命周期 */
beforeLoad?: lifecycle;
/** 没有做生命周期改造的子应用不会调用 */
beforeMount?: lifecycle;
afterMount?: lifecycle;
beforeUnmount?: lifecycle;
afterUnmount?: lifecycle;
/** 非保活应用不会调用 */
activated?: lifecycle;
deactivated?: lifecycle;
};
export { Props }
webpack.config.js
const { Configuration } = require('webpack')
const path = require('path')
/**
* @type {Configuration} // webpack 配置的智能提示
*/
const config = {
entry: './src/index.ts',
output: {
filename: 'index.js',
path: path.resolve(__dirname, 'lib'),
library: 'wujievue',
libraryTarget: 'umd',
umdNamedDefine: true
},
// 这两个文件不用打包到index.js文件中
externals: {
vue: 'vue',
wujie: 'wujie'
},
module: {
rules: [
{
test: /\.ts$/,
use: 'swc-loader' // swc 打包速度相比于babel更快
}
]
},
mode: 'none',
}
module.exports = config
无界官网: 无界