微前端之实践子应用的注册、路由拦截和获取首个子应用

编程入门 行业动态 更新时间:2024-10-23 03:22:48

微前端之实践子应用的注册、路由拦截和获取<a href=https://www.elefans.com/category/jswz/34/1769465.html style=首个子应用"/>

微前端之实践子应用的注册、路由拦截和获取首个子应用

一、微前端之实践子应用的注册、路由拦截和获取首个子应用
  1. 子应用的注册,如下所示:
  • 首先需要一个子应用注册的列表,在主应用 mainstore 文件夹中,新建 sub.js,对外暴露 subNavList 这个子应用的列表。subNavList 是一个数组,每一个子元素都是一个子应用,name 是子应用名称,唯一 IDentry 是子应用的入口,获取到子应用的文件;container 是子应用的渲染内容,显示在哪个容器中;activeRule 是子应用激活路由,根路由内容,激活的规则,loading 是子应用的加载状态;loading 是每一个子应用的信息,sub.js,代码如下:
import { loading } from '../store'
import * as appInfo from '../store'export const subNavList = [{name: 'react15',entry: '//localhost:9002/', loading,container: '#micro-container', activeRule: '/react15', appInfo,},{name: 'react16',entry: '//localhost:9003/',loading,container: '#micro-container',activeRule: '/react16',appInfo,},{name: 'vue2',entry: '//localhost:9004/',loading,container: '#micro-container',activeRule: '/vue2',appInfo,},{name: 'vue3',entry: '//localhost:9005/',loading,container: '#micro-container',activeRule: '/vue3',appInfo,},
];
  • 在主应用 mainstore 文件夹中,有 header.js、loading.js、nav.js、sub.jsindex.js,loading.js,代码如下:
import { ref } from 'vue';
export let loadingStatus = ref(true);
export const changeLoading = type => loadingStatus.value = type;
  • header.js,代码如下:
import { ref } from 'vue';
export const headerStatus = ref(true);
export const changeHeader = type => headerStatus.value = type;
  • nav.js,代码如下:
import { ref } from 'vue';
export const navStatus = ref(true);
export const changeNav = type => navStatus.value = type;
  • index.js,代码如下:
export * as loading from './loading';
export * as header from './header';
export * as nav from './nav';
  • 在主应用 main 中,main.js,通过 registerAppsubNavList 注册到 util 下的 index.js,微前端框架中,main.js,代码如下:
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import { subNavList } from './store/sub'
import { registerApp } from './util'registerApp(subNavList);
createApp(App).use(router()).mount('#micro_web_main_app');
  • 在主应用 main 中,util 下的 index.js,对外暴露 registerApp,通过将传入的子应用注册列表 list 注册到微前端框架里,registerMicroApps,同时也传入了主应用的生命周期,beforeLoad 开始加载,mounted 渲染完成,destoryed 卸载完成。通过调用 start 开启微前端框架,util 下的 index.js,代码如下:
import { registerMicroApps, start, createStore } from '../../micro'import { loading } from '../store'const store = createStore()
// const storeData = store.getStore()window.store = store
store.subscribe((newValue, oldValue) => {console.log(newValue, oldValue, '---')
})
// store.update({ ...storeData, a: 1 })export const registerApp = (list) => {registerMicroApps(list, {beforeLoad: [() => {loading.changeLoading(true)console.log('开始加载')}],mounted: [() => {loading.changeLoading(false)console.log('渲染完成')}],destoryed: [() => {console.log('卸载完成')}]})start()
}
  • micro 微前端框架中,之前调用的,registerMicroAppsmicro 下的 start.js 中,它需要使用到 micro 下的 constsubApps.js,其中 list 是统一管理子应用列表,getList 是获取子应用列表,setList 是将子应用列表注册到 list 中,subApps.js,代码如下:
let list = [] 
export const getList = () => list 
export const setList = appList => list = appList 
  • micro 下的 start.js 中,对外暴露 registerMicroApps 这个方法,传入子应用注册列表 appList 和主应用的生命周期 lifeCycle,分别调用 setListsetMainLifecycle 进行注册设置,代码如下:
export const registerMicroApps = (appList, lifeCycle) => {setList(appList);setMainLifecycle(lifeCycle);// window.appList = appList;
}
  1. 路由拦截,如下所示:
  • 首先需要在 micro 微前端框架中的 start.js,调用 rewriteRouter 方法实现路由拦截。在 router 下的 rewriteRouter.js 中,对外暴露出 rewriteRouter,重写 window 的路由跳转。patchRouter 接收两个参数,原生的事件、事件的名称,所有触发 pushStatereplaceState 的事件都会被监听到,window.history.pushStatewindow.history.replaceState。通过 window.addEventListener 事件绑定 micro_pushmicro_replace,通过 window.onpopstate 事件监听,监听返回事件,当点了返回按钮后 turnApp 就会执行,rewriteRouter.js,代码如下:
import { patchRouter } from '../utils'
import { turnApp } from './routerHandle'export const rewriteRouter = () => {window.history.pushState = patchRouter(window.history.pushState, 'micro_push');window.history.replaceState = patchRouter(window.history.replaceState, 'micro_replace');window.addEventListener('micro_push', turnApp);window.addEventListener('micro_replace', turnApp);window.onpopstate = async function () {await turnApp()}
}
  • patchRouter 是在 micro 下的 util 中的 index.js,给当前的路由跳转打补丁。通过 new Event 创建新的事件,通过 globalEvent.apply 传递过来的原生事件 globalEvent,代替函数的执行,通过 window.dispatchEvent 触发创建的事件,代码如下:
export const patchRouter = (globalEvent, eventName) => {return function () {const e = new Event(eventName)globalEvent.apply(this, arguments) window.dispatchEvent(e) }
}
  • turnApp 是在 micro 下的 router 中的 routerHandle.js,如果子应用发生改变在里面可以执行微前端的生命周期执行,代码如下:
import { isTurnChild } from '../utils'
import { lifecycle } from '../lifeCycle'
export const turnApp = async () => {if (isTurnChild()) {await lifecycle()}
}
  1. 获取首个子应用,如下所示:
  • registerApp 中调用 micro 下的 start.js,对外暴露的 start 方法启动微前端框架。通过 getList 首先验证当前子应用列表是否为空,如果子应用列表为空,抛出异常。如果子应用列表非空,有子应用的内容, 查找到符合当前路由的子应用。如果当前没有在使用的子应用, 抛出一个错误,请访问正确的连接,访问一个默认的路由,通常为首页或登录页面,window.history.pushState 跳转到对应的 url 上。若查找到子应用的内容并且 hash 值存在,进行标记,将当前 app 的内容设置为 app.activeRulestart.js,代码如下:
import { setList, getList } from './const/subApps'
import { currentApp } from './utils'
import { rewriteRouter } from './router/rewriteRouter'
import { setMainLifecycle } from './const/mainLifeCycle'
import { prefetch } from './loader/prefetch'
import { Custom } from './customevent'const custom = new Custom()
custom.on('test', (data) => {console.log(data)
})window.custom = custom;rewriteRouter();export const registerMicroApps = (appList, lifeCycle) => {setList(appList);setMainLifecycle(lifeCycle);// window.appList = appList;
}export const start = () => {const apps = getList();if (!apps.length) {throw Error('子应用列表为空, 请正确注册');}const app = currentApp();const { pathname, hash } = window.location;if (!hash) {window.history.pushState(null, null, '/vue3#/index'); }if (app && hash) {const url = pathname + hash;window.__CURRENT_SUB_APP__ = app.activeRule;window.history.pushState('', '', url);}prefetch();
}
  • 调用 currentApp 时,是在 microutils 下的 index.js,通过 window.location.pathname 获取到当前子应用的路由 activeRule,调用 filterApp 子应用在命中后就会返回,isTurnChild 是判断子应用是否做了切换,index.js,代码如下:
import { getList } from "../const/subApps";
export const patchRouter = (globalEvent, eventName) => {return function () {const e = new Event(eventName); globalEvent.apply(this, arguments); window.dispatchEvent(e); }
}export const currentApp = () => {const currentUrl = window.location.pathname;return filterApp('activeRule', currentUrl);
}export const findAppByRoute = (router) => {return filterApp('activeRule', router);
}export const filterApp = (key, value) => {const currentApp = getList().filter(item => item[key] === value);return currentApp && currentApp.length ? currentApp[0] : {};
}export const isTurnChild = () => {const { pathname, hash } = window.location;const url = pathname + hash;const currentPrefix = url.match(/(\/\w+)/g);if (currentPrefix &&(currentPrefix[0] === window.__CURRENT_SUB_APP__) &&hash === window.__CURRENT_HASH__) {return false;}window.__ORIGIN_APP__ = window.__CURRENT_SUB_APP__;const currentSubApp = window.location.pathname.match(/(\/\w+)/);if (!currentSubApp) {return false}window.__CURRENT_SUB_APP__ = currentSubApp[0];window.__CURRENT_HASH__ = hash;return true;
}

更多推荐

微前端之实践子应用的注册、路由拦截和获取首个子应用

本文发布于:2024-02-11 11:10:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1680665.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:首个   路由

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!