【qiankun微前端】基座主应用(vue2)+多个微应用(任意框架)

前言

前段时间对我们已有的工程进行了微前端改造,后来思考一下微前端的本质,查询了不少资料,从qiankun微前端示例中学到了不少。

微前端的核心,似乎应该是一个基座应用(含登录页,layout页,404和首页等),多个子应用(任意框架,提供内部页面内容),下面就对这个思路进行实现讲解:
在这里插入图片描述
在这里插入图片描述

一、主应用

在这里插入图片描述

1、主应用主要提供 Login、Layout、Home、404等基础页面。
2、通过提供qiankun的initGlobalState、registerMicroApps、start等完成主应用的qiankun注册、子应用的注册和数据初始化,监听。

// router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import store from '@/store'
import Login from '@/views/Login'
import Home from '@/views/Home'
import Layout from '@/views/Layout'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'

Vue.use(VueRouter)

// 路由
const constantRoutes = [
  {
   
    path: '/login',
    name: 'login',
    component: Login,
    meta: {
    isTabs: false, isSide: false, moduleName: 'main', title: '登录' }
  },
  {
   
    path: '/',
    name: 'Layout',
    component: Layout,
    redirect: process.env.VUE_APP_DEFAULT_APP, // 默认加载的路由
    children: [
      {
   
        path: '/home',
        name: 'Home',
        component: Home,
        meta: {
    isTabs: false, isSide: false, moduleName: 'main', title: '首页' }
      }
    ]
  }
]

const createRouter = () => {
   
  return new VueRouter({
   
    mode: 'history',
    routes: constantRoutes,
    isAddAsyncMenuData: false
  })
}

// 处理重复点击同一个路由报错的问题
const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push (location) {
   
  return originalPush.call(this, location).catch((err) => err)
}

const router = createRouter()

/**
 * 重置注册的路由导航map
 * 主要是为了通过addRoutes方法动态注入新路由时,避免重复注册相同name路由
 */
const resetRouter = () => {
   
  const newRouter = createRouter();
  router && (router.matcher = newRouter.matcher);
};

router.beforeEach((to, from, next) => {
   
  NProgress.start()
  // 菜单当前选中及页面持久
  if (to.path !== '/login') {
   
    store.commit('permission/UPDATE_CURRENT_MODULE_NAME', to.meta.moduleName)
    store.commit('permission/UPDATE_CURRENT_PAGE', to.path)
  }
  // 首页的时候组装左侧导航数据
  // if (to.path === '/home') {
   
  //   store.commit('permission/UPDATE_SUB_MENU', true)
  // }
  if (!router.options.isAddAsyncMenuData) {
   
    store.dispatch('permission/generateRoutes').then((accessRoutes) => {
   
      // 根据用户权限生成可访问的路由表
      for (let i = 0, length = accessRoutes.length; i < length; i += 1) {
   
        const element = accessRoutes[i]
        router.addRoute(element)
      }
      router.options.isAddAsyncMenuData = true
      next({
    ...to, replace: true }) // hack方法 确保addRoutes已完成
    })
  } else {
   
    next()
  }
})

router.afterEach(() => {
   
  NProgress.done()
})

export {
    constantRoutes, resetRouter };

export default router
// store/modules/permission.js
import http from 'axios'
import {
    constantRoutes } from '@/router'
import Layout from '@/views/Layout'
import {
    homeMenuData } from '../../utils'

const permission = {
   
  namespaced: true,
  state: () => ({
   
    routers: null,
    menuList: [],
    subMenu: [],
    currentModuleName: 'main',
    currentPage: '/home'
  }),
  mutations: {
   
    // 当前模块
    UPDATE_CURRENT_MODULE_NAME (state, payload) {
   
      sessionStorage.setItem('currentApp', payload)
      state.currentModuleName = payload
    },
    // 当前页面
    UPDATE_CURRENT_PAGE (state, payload) {
   
      sessionStorage.setItem('currentPage', payload)
      state.currentPage = payload
    },
    // 菜单数据
    UPDATE_MENU_LIST (state, payload) {
   
      state.menuList = payload
    },
    // 左侧菜单数据,子应用菜单数据
    UPDATE_SUB_MENU (state, payload) {
   
      state.subMenu = []
      // if (typeof payload === 'boolean') {
   
      //   state.subMenu.push(homeMenuData)
      //   return
      // }
      if (typeof payload === 'object') {
   
        state.subMenu = payload
      }
    },
    // 路由数据
    UPDATE_ROUTERS (state, payload) {
   
      state.routers = constantRoutes.concat(payload)
    }
  },
  actions: {
   
    generateRoutes ({
     commit }) {
   
      return new Promise((resolve) => {
   
        // 向后端请求路由数据
        http.get('/mock/menu.json').then((res) => {
   
          const data = res.data
          data.unshift(homeMenuData) // 添加首页菜单,默认主应用的菜单信息在这里
          commit('UPDATE_MENU_LIST', data)
          let routes = []
          for (let i = 0; i < data.length; i++) {
   
            const module = data[i]
            const route = getMenuItem(module.menuList)
            routes = [...routes, ...route]
          }
          routes.push({
   
            path: '*',
            name: 'notfound',
            component: () => import('@/views/404.vue')
          })
          commit('UPDATE_ROUTERS', routes)
          resolve(routes)
        })
      })
    }
  },
  getters: {
   }
}

// 组装路由数据
function getMenuItem (menus) {
   
  let routers = []
  for (let index = 0; index < menus.length; index++) {
   
    const menu =</
  • 5
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值