vite+vue3+pinia实现动态注册懒加载路由教程

 更新时间:2025年04月28日 14:16:35   作者:Tt涛㏒  
这篇文章主要介绍了vite+vue3+pinia实现动态注册懒加载路由教程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

模块版本

  • vite:^5.4.10
  • vue:^3.5.12
  • vue-router:^4.4.5
  • pinia:^2.2.6
  • pinia-plugin-persistedstate:^4.1.3(pinia持久化插件)

业务需求说明

每个程序都要满足不同的业务需求,以下代码只是满足我当前的业务需求

  • 后端保存了每个用户的前端路由列表信息
  • 前端默认路径为’/login’,比如www.xxxx.com访问默认显示login页面
  • 前端默认注册静态路由’/login’,并重定向到路径’/’
  • 用户点击登录后获取路由列表,通过addRoute注册路由

router代码

import {createRouter, createWebHistory} from 'vue-router'
import type {Router} from 'vue-router'

const router: Router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/',
      component: () => import('@/views/Login.vue')
    },
    {
      path: '/login',
      name: 'login',
      meta: {
        navBar: false,
        token: false
      },
      component: () => import('@/views/Login.vue')
    }
  ],
})

export default router

Login页面(ts+setup)

<script lang="ts" setup>
  import {ref} from "vue"
  import {useRouter} from 'vue-router'
  import {loginApi} from '@/api/login/loginApi'
  import {useUserInfo, useMyToken} from '@/stores/counter'
  import type {RouterListItem} from '@/types/login'

  const userInfo = useUserInfo()
  const myToken = useMyToken()
  const router = useRouter()

  /** 用户输入账号 */
  const userName = ref<string>('')
  /** 用户输入的密码 */
  const password = ref<string>('')

  /** 登录API */
  const logon = async () => {
    /** 发送登录请求,携带用户账号和密码信息 */
    loginApi(userName.value, password.value).then((res) => {
      /** 后端返回的用户信息和路由列表,写入pinia */
      userInfo.setUserInfo(res.result.info)
      /** 用户token信息,写入pinia */
      myToken.setMyToken(res.result.token)
      /** 调取pinia内的方法注册路由 */
      userInfo.registeredRoute()
      /** 由于后端返回的路由列表是JSON格式,需要转换 */
      let routerListArr: RouterListItem[] = []
      if (userInfo.userInfo !== undefined) {
        /** 转换路由信息 */
        routerListArr = JSON.parse(userInfo.userInfo?.router_list)
      }
      /** 跳转到用户路由列表中的第一个路由 */
      router.replace(routerListArr[0].path)
    }, (err) => {
      /** 错误提示 */
      ElMessage({
        message: err.response.data.message,
        type: 'error'
      })
    })
  }
</script>

pinia代码

import {ref} from 'vue'
import {defineStore} from 'pinia'
import type {RouterListItem, UserInfo} from '@/types/login'
/** 导入的是自己的路由文件 src-router-index.ts */
import myRouter from '@/router/index'

/** 用户信息相关 */
export const useUserInfo = defineStore(
  'userInfo',
  () => {
    /** 用户信息 */
    const userInfo = ref<UserInfo | undefined>(undefined)
    
    /** 存储用户信息方法 */
    const setUserInfo = (info: UserInfo): void => {
      userInfo.value = info
    }
    /** 清除用户信息方法-用于退出登录或token验证失败 */
    const clearUserInfo = (): void => {
      userInfo.value = undefined
    }
    /** 注册路由方法 */
    const registeredRoute = () => {
      /** 判断userInfo.value是否为undefined,不是则进入 */ 
      if (userInfo.value !== undefined) {
        /** 由于我的后端返回路由列表是JSON格式,需要转换后使用 */
        const routerListArr: RouterListItem[] = JSON.parse(userInfo.value?.router_list)
        /** 通过循环添加路由 */
        for (const item of routerListArr) {
          const route = {
            path: item.path,
            name: item.name,
            meta: {
              navBar: item.meta.navBar,
              token: item.meta.token
            },
            /** 懒加载导入vue页面
                由于我的后端返回的component名称是带有后缀名的,直接导入vite会报警告,虽然不影响使用,但是安全起见
                还是替换了为好,这里使用replace将.vue替换为空
            */
            component: () => import(`../views/${item.component.replace('.vue', '')}.vue`)       
          }
          myRouter.addRoute(route)
        }
      }
    }
    
    return {
      userInfo,
      setUserInfo,
      clearUserInfo,
      registeredRoute
    }
  },
  { 
     /** pinia持久化 */
    persist: true
  })

/** 用户token相关 */
export const useMyToken = defineStore(
  'myToken',
  () => {
    /** token信息 */
    const myToken = ref<string | undefined>(undefined)
   
    /** 存储token信息方法 */
    const setMyToken = (token: string) => {
      myToken.value = token
    }
    /** 清除token信息方法-用于退出登录或token验证失败 */
    const clearMyToken = () => {
      myToken.value = undefined
    }
    
    return {
      myToken,
      setMyToken,
      clearMyToken
    }
  },
  {
    /** pinia持久化 */
    persist: true
  })

关于替换.vue后缀的说明

导入必须以 或 开头。./…/

所有导入都必须相对于导入文件开始。导入不应以变量、绝对路径或裸导入开头:

// Not allowed
import(bar);
import(`${bar}.js`);
import(`/foo/${bar}.js`);
import(`some-library/${bar}.js`);

导入必须以文件扩展名结尾

文件夹可能包含您不打算导入的文件。因此,我们要求导入在导入的静态部分中以文件扩展名结尾。

// Not allowed
import(`./foo/${bar}`);
// allowed
import(`./foo/${bar}.js`);

导入到您自己的目录必须指定文件名模式

如果您导入自己的目录,则最终可能会得到您不打算导入的文件,包括您自己的模块。因此,需要提供更具体的文件名模式:

// not allowed
import(`./${foo}.js`);
// allowed
import(`./module-${foo}.js`);

详细信息见文档:dynamic-import-vars#limitations

main代码(vue的main.ts文件内)

import './assets/main.css'
import {createApp} from 'vue'
import App from './App.vue'
import router from './router'
/** 导入createPinia用于创建pinia */
import {createPinia} from 'pinia'
/** 导入ElementPlus */
import ElementPlus from 'element-plus'
/** 导入ElementPlus国际化文件-中文 */
import zhCn from 'element-plus/es/locale/lang/zh-cn'
/** 导入pinia持久化插件 */
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
/** 导入pinia内的useUserInfo,用于动态注册路由 */
import {useUserInfo} from '@/stores/counter'
/** 导入el-loading样式 */
import 'element-plus/theme-chalk/el-loading.css'
/** 导入el-message样式 */
import 'element-plus/theme-chalk/el-message.css'
import type {Pinia} from 'pinia'


const app = createApp(App)
/** 创建pinia */
const pinia: Pinia = createPinia()
/** 注册piniaPluginPersistedstate持久化插件 */
pinia.use(piniaPluginPersistedstate)
/** 注册pinia */
app.use(pinia)
/** 获取pinia内的userInfo,用于动态注册路由 */
const userInfo = useUserInfo()
/** 动态注册路由,并且防止刷新页面导致路由丢失
    这里直接调用userInfo.registeredRoute()会不生效,需要写到函数内部,再调用函数
    并且需要写在app.use(router)之前
 */
const addRouter = () => {
  userInfo.registeredRoute()
}
addRouter()
app.use(router)

/** 注册ElementPlus,并使用中文模式 */
app.use(ElementPlus, {
  locale: zhCn,
})


app.mount('#app')

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • vue webpack build资源相对路径的问题及解决方法

    vue webpack build资源相对路径的问题及解决方法

    这篇文章主要介绍了vue webpack build资源相对路径的问题,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-06-06
  • vue-cli脚手架build目录下utils.js工具配置文件详解

    vue-cli脚手架build目录下utils.js工具配置文件详解

    这篇文章主要介绍了vue-cli脚手架build目录下utils.js工具配置文件详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-09-09
  • Vue项目业务逻辑模块介绍

    Vue项目业务逻辑模块介绍

    这篇文章主要介绍了Vue项目业务逻辑,不同的项目有不同的功能,不同的功能需要不同的实现,实现这些核心功能的代码就叫业务逻辑。所以说业务逻辑是指一个实体单元为了向另一个实体单元提供服务,应该具备的规则与流程
    2022-11-11
  • 利用vuex-persistedstate将vuex本地存储实现

    利用vuex-persistedstate将vuex本地存储实现

    这篇文章主要介绍了利用vuex-persistedstate将vuex本地存储的实现,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-04-04
  • Vue-Element-Admin前端接入SSO的方法步骤

    Vue-Element-Admin前端接入SSO的方法步骤

    本文主要介绍了Vue-Element-Admin前端接入SSO的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-04-04
  • Vue组件之极简的地址选择器的实现

    Vue组件之极简的地址选择器的实现

    这篇文章主要介绍了Vue组件之极简的地址选择器的实现,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-05-05
  • 使用vite构建vue3项目的方法步骤

    使用vite构建vue3项目的方法步骤

    本文主要介绍了使用vite构建vue3项目的方法步骤,vite支持性肯定比传统的打包工具好,下面我们就来介绍一下使用vite构建vue3项目,感兴趣的可以参考一下
    2023-05-05
  • LRU算法在Vue内置组件keep-alive中的使用

    LRU算法在Vue内置组件keep-alive中的使用

    LRU算法全称为least recently use 最近最少使用,核心思路是最近被访问的以后被访问的概率会变高,那么可以把之前没被访问的进行删除,维持一个稳定的最大容量值,从而不会导致内存溢出。
    2021-05-05
  • Vue3中使用pnpm搭建monorepo开发环境

    Vue3中使用pnpm搭建monorepo开发环境

    这篇文章主要为大家介绍了Vue3中使用pnpm搭建monorepo开发环境示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08
  • vue项目中引入Sass实例方法

    vue项目中引入Sass实例方法

    在本文里小编给大家整理的是关于vue项目中引入Sass的相关知识点内容,有需要的朋友们可以测试参考下。
    2019-08-08

最新评论