微前端之注册子应用与路由拦截

38 阅读1分钟

本文主要内容包括:如何在主应用里注册子应用?如何实现路由拦截?

注册子应用

先定义子应用列表。

export const subNavList = [
  {
    name: 'react15', // 子应用名称
    activeRule: '/react15', // 激活路由
    container: '#micro-container', // 展示子应用的容器
    entry: '//localhost:9002/' // 子应用的入口
  },
  {
    name: 'react16',
    activeRule: '/react16',
    container: '#micro-container',
    entry: '//localhost:9003/'
  },
  {
    name: 'vue2',
    activeRule: '/vue2',
    container: '#micro-container',
    entry: '//localhost:9004/'
  },
  {
    name: 'vue3',
    activeRule: '/vue3',
    container: '#micro-container',
    entry: '//localhost:9005/'
  },
]

// 子应用列表也可以存储在 window 中,但不推荐,容易造成全局变量污染。
// 这里把子应用列表放在 list 变量里,还添加了对应的 get 和 set 方法。

let list = []

/** 获取所有子应用列表 */
export const getList = () => list

/** 将需要注册的子应用列表放置到子应用容器里 */
export const setList = appList => list = appList

export const registerMicroApps = (appList) => {
  setList(appList)
}

export const registerApp = (list) => {
  // 注册到微前端框架里
  registerMicroApps(list)
}

// 主应用 createApp 之前调用
registerApp(subNavList)

路由拦截

入口函数是 rewriteRouter

// 子应用是否做了切换,window.__CURRENT_SUB_APP__ 保证只触发一次,后面会设置值
export const isTurnChild = () => {
  if (window.__CURRENT_SUB_APP__ === window.location.pathname) {
    return false
  } 
  return true
}

export const turnApp = () => {
  if (isTurnChild()) {
    console.log('路由切换了');
  }
}

// 给当前的路由跳转打补丁
export const patchRouter = (globalEvent, eventName) => {
  return function() {
    const e = new Event(eventName)
    globalEvent.apply(this, arguments)
    window.dispatchEvent(e)
  }
}

// 重写 window 的路由跳转
const rewriteRouter = () => {
  window.history.pushState = patchRouter(window.history.pushState, 'micro_push')
  window.history.replaceState = patchRouter(window.history.replaceState, 'micro_replace')
  // 通过监听自己创建的事件名称来添加回调函数 turnApp
  window.addEventListener('micro_push', turnApp)
  window.addEventListener('micro_replace', turnApp)
  // 监听返回事件
  window.onpopstate = () => {
    turnApp()
  }
}

// 实现路由拦截
rewriteRouter()