vue3+pinia+vite动态路由的实现

做法:

在utils文件夹>>>map-menus.ts文件,使用for循环当前用户菜单数据的方式动态生成需要动态挂载的路由数组。在用户登录成功以后把这些路由数据动态挂载。

1. 创建路由

router>>index.ts

import { login_token } from '@/global/constance.'
import { localCache } from '@/utils/cache'
import { createRouter, createWebHashHistory } from 'vue-router'
import { firstRoute } from '@/utils/map-menus'
const router = createRouter({
  history: createWebHashHistory(),
  //映射关系:path=>component
  routes: [
    {
      path: '/',
      redirect: '/main'
    },
    {
      path: '/login',
      component: () => import('../view/login/Login.vue')
    },
    //----------------------------------------------------------------------------------------
    {
      path: '/main',
      name: 'main',
      // children:[],
      // 注意这里的name要写,这样调用addRoute('main',item)方法时才会把item添加到children数组中
      component: () => import('../view/main/Main.vue')
    },
     //----------------------------------------------------------------------------------------
    {
      path: '/:pathMatch(.*)',
      component: () => import('../view/not-found/NotFound.vue')
    }
  ]
})
const token = localCache.getCache(login_token)
//导航守卫-------------------------------------------------------------------------------------
router.beforeEach((to) => {
  console.log('router.beforeEach((to) >>')
  // if (to.path.startsWith('main') && !token)如果登录后里面所有的页面都是main开头页可以这样写
  if (to.path !== '/login' && !token) {
    return '/login'
  // 当用户输入main页面或登录成功后,默认跳转到菜单的第一项
  } else if (to.path ==='/main' && token) {
    return firstRoute.url
  }
})
export default router

2.根据当前用户的菜单数据,通过for循环生成main路由下的所有children数据

文件位置:utils>>>map-menus.ts

import type { RouteRecordRaw } from 'vue-router'

// 获取所有菜单url地址
const localRouter: RouteRecordRaw[] = []
// const files: Record<string, any> = import.meta.glob(
//   '../../view/main/**/*.vue',
//   { eager: true }
// )
//  { eager: true }立即加载函数,将结果给出

//从文件系统导入多个模块 ../../view/main/**/*.vue
const files: Record<string, any> = import.meta.glob('../view/main/**/*.vue', {
  eager: true
})

export let firstRoute: any = null
//获取当前用户所有main权限路由,将将要动态挂载的数据localRouter通过调用getRouterItem方法暴露出去
export function getRouterItem(menueInfo: any[]) {
  //for循环拿到需要动态挂载在main的children下的路由数组
  for (const item of menueInfo) {
    for (const item2 of item.children) {
      const url: string = `../view${item2.url}/${item2.url.split('/')[3]}.vue`
      //拿到component模块
      const module = files[url]?.default
      // 记录第一个被匹配的菜单
      if (!firstRoute && item) firstRoute = item2
      // 通过for循环把main下的children中的每个对象oush进localRouter
      localRouter.push({
        path: item2.url,
        component: module
      })
    }
  }
  return localRouter
}

3.用户登录成功后,调用store>>>login>>>login.ts里action中的loginAccountAction方法

store>>>login>>>login.ts

import { defineStore } from 'pinia'
import {
  accountLoginRequest,
  getMenueInfoRequest,
  getUserInfoRequest
} from '@/service/login/login'
import { localCache } from '@/utils/cache'
import { login_token } from '@/global/constance.'
import type { IAccount } from '@/type'
import router from '@/router'
// 获取用户可登录的url地址
// import localRouter from '@/router/main'
import { getRouterItem } from '@/utils/map-menus'
//----------------------------------------------------------

//将token定义为变量,避免使用的时候拼写错误
// const login_token = 'token'
interface ILoginState {
  token: string
  userInfo: any
  menueInfo: any
}
const useLoginStore = defineStore('login', {
  state: (): ILoginState => ({
    token: '',
    userInfo: {},
    menueInfo: []
  }),
  actions: {
    async loginAccountAction(account: IAccount) {
      // 发送登录请求,将获取的结果进行赋值
      const loginResult = await accountLoginRequest(account)
      //发送用户信息请求

      // 将数据保存到pinia中
      const id = loginResult.data.id
      this.token = loginResult.data.token
      const name = loginResult.data.name
      // 为避免刷新时数据消失,将请求存储到localhost
      localCache.setCache(login_token, this.token)
      // 请求用户信息
      const userInfo = await getUserInfoRequest(id)
      this.userInfo = userInfo.data
      console.log('this.userInfo :>> ', this.userInfo)

      // 获取菜单信息
      const menueInfo = await getMenueInfoRequest(id)
      // console.log('menueInfo :>> ', menueInfo)
      this.menueInfo = menueInfo?.data ?? []

      localCache.setCache('menueInfo', this.menueInfo)
      localCache.setCache('userInfo', this.userInfo)

      //====================
      //动态挂载路由
      //调用router里暴露的dynamicAddRoute方法动态挂载路由的方法
      // dynamicAddRoute()
      if (menueInfo.length > 0) {
        const localRoutes = getRouterItem(menueInfo)
        localRoutes.forEach((item) => {
          // console.log('item :>> ', item)
          router.addRoute('main', item)
        })
      }
      //================================
      //页面跳转到main
      router.push('/main')
    },
    loadingLocalCacheAction() {      //解决用户刷新时,路由信息丢失
      const token = localCache.getCache(login_token)
      const userInfo = localCache.getCache('userInfo')
      const menueInfo = localCache.getCache('menueInfo')
      //  当有用户信息时,动态挂载路由
      if (token && userInfo && menueInfo) {
        const localRoutes = getRouterItem(menueInfo)
        localRoutes.forEach((item) => {
          router.addRoute('main', item)
        })
      }
    }
  }
})
export default useLoginStore

4.创建registerStore方法,在挂载app,注册pinia后再调用piniade的useLoginStore里的loadingLocalCacheAction方法。

store>>>index.ts

import { createPinia } from 'pinia'
import type { App } from 'vue'
import useLoginStore from './login/login'
const pinia = createPinia()
function registerStore(app: App<Element>) {
  app.use(pinia)
  const loginStore = useLoginStore()
  loginStore.loadingLocalCacheAction()
}
export default registerStore

5.在main.ts中引入store>>>index.ts的registerStore,注意要将此方法放在app.use(router)前面

import { createApp } from 'vue'
import App from './App.vue'
import 'normalize.css'
import './assets/css/index.less'
import './assets/main.css'
import router from './router'
import registerIcon from './global/register-icons'
import registerStore from './store'
console.log('main.ts :>> ')
const app = createApp(App)
// app.use(pinia)
//将通过引入registerStore的方式代码看起来更舒适
app.use(registerStore)
// 注意router要放在后面动态添加的路由才能挂载成功
app.use(router)
app.use(registerIcon)
app.mount('#app')
// createApp(App).use(router).mount('#app')

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值