vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > vite+vue3+pinia实现动态注册懒加载路由

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

作者:Tt涛㏒

这篇文章主要介绍了vite+vue3+pinia实现动态注册懒加载路由教程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

模块版本

业务需求说明

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

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')

总结

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

您可能感兴趣的文章:
阅读全文