【 Vue3 + Vite + setup语法糖 + Pinia + VueRouter + Element Plus 第四篇】(持续更新中)

在第三篇中,我们主要学习了组件的封装与使用以及 组件间传值Element Plus 表格、表单的用法

本期需要掌握的知识如下:

  • mixin 公共方法封装和使用
  • 项目中导入 VueRouter
  • 使用 VueRouter 完成 路由跳转、获取路由信息
  • VueRouter 模块化、路由拦截器
  • 权限路由配置

下期需要掌握的知识如下:

  • 项目中导入 Pinia
  • 使用 Pinia 完成登录存储用户信息,并在页面使用/调用 Pinia 方法/数据
  • 持久化 Pinia 数据
  • 路由拦截中使用 Pinia 代替 本地存储 Stroage

1. mixin公共方法封装

src目录下新建 mixin目录,并在该目录下新建 index.js
在这里插入图片描述

// 引入 element 弹窗提示组件
import {
    
     ElMessageBox } from 'element-plus'
// 引入进度条组件
import nprogress from "nprogress"
// 设置进度条loading样式
nprogress.configure({
    
     showSpinner: false })

// 封装 弹窗确认组件
export const MessageBoxMixins = async tips => {
    
    
  try {
    
    
    let res = await ElMessageBox.confirm(tips, '提示', {
    
    
      confirmButtonText: '确认',
      cancelButtonText: '取消',
      type: 'warning'
    })
    return res
  } catch (err) {
    
    
    return err
  }
}
// 封装 localStorage 存储方法
export const setlocalstroage = (key, val) => {
    
    
  return localStorage.setItem(key, val)
}
export const setsessionstroage = (key, val) => {
    
    
  return sessionStorage.setItem(key, val)
}
// 封装 localStorage 设置方法
export const getlocalstroage = key => {
    
    
  return localStorage.getItem(key)
}
export const getsessionstroage = key => {
    
    
  return sessionStorage.getItem(key)
}
// 封装 sessionStorage 清除方法
export const clearSession = () => {
    
    
  sessionStorage.clear()
}
export const clearLocal = () => {
    
    
  return localStorage.clear()
}
// 封装 sessionStorage 清除某一项方法
export const removeSessionItem = key => {
    
    
  return sessionStorage.removeItem(key)
}
export const removeLocalItem = key => {
    
    
  return localStorage.removeItem(key)
}
// 封装 开启进度条方法
export const showNprogress = () => {
    
    
  nprogress.start()
}
// 封装 关闭进度条方法
export const hideNprogress = () => {
    
    
  nprogress.done()
}

2. vue-router 安装及配置

使用 npm i vue-router@4 安装 VueRouter

main.js

import {
    
     createApp } from 'vue'
import './style.css'
import App from './App.vue'
// 导入 router
import router from './router'

import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'

import axios from 'axios'
import VueAxios from 'vue-axios'

// 在此使用 router
createApp(App).use(router).use(ElementPlus, {
    
     locale: zhCn }).use(VueAxios, axios).mount('#app')

创建模块化路由

目录结构如下

index.js为根路由,所有 modules下的路由都会在 index.js导入,并最终在 index.js合并后统一导出

注: 所有的模块化路由都建议放到 modules目录下,更具备语义化

在这里插入图片描述

home.js

// 导出 home 路由
export const homeRoutes = [
  {
    
    
    path: '/',
    // 访问项目根路径的时候会重定向到 /home
    // 下面会根据 token 判断用户是否登录,在拦截器中让它跳转登录页面
    redirect: '/home'
  },
  {
    
    
    name: 'home',
    path: '/home',
    // meta document 压面的 title 值, 也会在路由拦截器中进行配置
    meta: {
    
    
      title: '首页'
    },
    // 路由懒加载
    component: () => import('@/views/home/index.vue')
  },
  {
    
    
    name: 'list',
    path: '/list/:id',
    meta: {
    
    
      title: '列表页'
    },
    component: () => import('@/views/list/index.vue')
  },
  // 404 页面,当用户访问不存在的路由时跳转到该页面
  // 后面也会在路由拦截器中进行配置
  {
    
    
    name: '404 Not Found',
    path: '/404',
    meta: {
    
    
      title: '404 Not Found'
    },
    component: () => import('@/views/NotFound/index.vue')
  }
]

login.js

export const loginRoutes = [
  {
    
    
    name: 'login',
    path: '/login',
    meta: {
    
    
      title: '登录'
    },
    component: () => import('@/views/login/index.vue')
  }
]

模块化路由已经创建完毕,我们需要对index.js进行配置

// 引入创建路由 创建 history 路由方法
import {
    
     createRouter, createWebHistory } from 'vue-router'
// 引入 home 路由
import {
    
     homeRoutes } from './modules/home'
// 引入 login 路由
import {
    
     loginRoutes } from './modules/login'
// 封装的 mixin 公共方法
import {
    
     getlocalstroage, clearSession, clearLocal, showNprogress, hideNprogress } from '@/mixin'

// 首先把你需要动态路由的组件地址全部获取
let modules = import.meta.glob('../views/**/*.vue')
// 设置标识 防止路由进入死循环
let flag = true

// 创建 router 
const router = createRouter({
    
    
  history: createWebHistory(), // 设置为 history 模式
  routes: [...loginRoutes, ...homeRoutes] // 合并路由
})

// 路由拦截器 前置钩子函数
router.beforeEach((to, from, next) => {
    
    
// 开启进度条
  showNprogress()
  // 判断有无 title 给 页面标题设置
  if (to.meta.title) {
    
    
    document.title = to.meta.title
  }
  const data = [{
    
    
      "name": "admin",
      "path": "/admin",
      "hidden": false,
      "meta": {
    
    
        "title": "首页"
      },
      "children": [
        {
    
    
          "name": "admin/user",
          "path": "user",
          "hidden": false,
          "meta": {
    
    
            "title": "用户管理"
          }
        },
        {
    
    
          "name": "admin/role",
          "path": "role",
          "hidden": false,
          "meta": {
    
    
            "title": "角色管理"
          }
        }
      ]
    }]
   // 下期讲 Pinia 的时候这里的数据会替换成 Pinia 的数据
  if (data.length > 0) {
    
    
  	addDynamicRoute(data)
    if (flag) {
    
    
     // 这里添加匹配 404 路由模式,必须在静态路由中先加上 /404 页面
      const NotFound = {
    
     path: '/:pathMatch(.*)*', redirect: '/404' }
      // 添加 404 路由页面
      router.addRoute(NotFound)
      // 这里是必须的 解决 Vue3 中 刷新页面导致路由失效问题
      next({
    
     ...to, replace: true })
      // 添加 router.options 只有添加了再能回去 下面我们会讲
      router.options.routes.push(JSON.parse(JSON.stringify(...animationRoute.value),NotFound))
      // 设置 falg 为 false 下次路由刷新将不会进入该循环 以防造成死循环
      flag = false
    }
  }
  // 因 login 页面不需要 token 就可以访问,所以我们在此判断
  if (to.path != '/login') {
    
    
  	// 获取 token
    let apiToken = getlocalstroage('user') ? JSON.parse(getlocalstroage('user')) : null
    if (!apiToken) {
    
    
      // 如果没有 token 清除掉存储并跳转 login 页面
      clearSession()
      clearLocal()
      next('/login')
    }
  }
  // 反之则放行
  next()
})

// 路由后置钩子  在此关闭进度条
router.afterEach(() => {
    
    
  hideNprogress()
})

// 添加动态路由,parent默认为home是首页最外层的路由name名
const addDynamicRoute = (useroute, parent) => {
    
    
  for (let i = 0; i < useroute.length; i++) {
    
    
    if (useroute[i].children && useroute[i].children.length > 0) {
    
    
      // 如果有嵌套路由 router.addRoute 接收的第一个参数为父组件 name 值
      // 如果不是 则不传
      router.addRoute({
    
     name: useroute[i].name, path: useroute[i].path, component: modules[`../views/${
      
      useroute[i].name}/index.vue`], meta: {
    
     title: useroute[i].meta.title }, hidden: useroute[i].hidden })
      // 递归添加动态路由
      addDynamicRoute(useroute[i].children, useroute[i].name);
    } else {
    
    
      router.addRoute(parent, {
    
     path: useroute[i].path, component: modules[`../views/${
      
      useroute[i].name}/index.vue`], meta: {
    
     title: useroute[i].meta.title }, hidden: useroute[i].hidden })
    }
  }
};

// 导出 router
export default router

注意此处有大坑

  1. Vue3 中的 嵌套路由前不能携带 / ,否则解析不成功
  2. 动态设置的路由必须 router.options.routes.push添加进去,否则在页面使用获取不到动态路由信息
  3. router.addRoute()方法使用后必须 next({ ...to, replace: true }) ,否则刷新后动态路由消失
  4. { path: '/:pathMatch(.*)*', redirect: '/404' }必须在最后添加该路由,否则匹配不到此路由后的路由

3. 路由在页面的使用

// 最简单的方法 在需要的页面导入 useRouter 方法
import {
    
     useRouter } from 'vue-router'
const Router = useRouter() // useRouter 是一个方法 使用 Router 接收它
// 页面加载完毕钩子函数
onMounted(() => {
    
    
  console.log(Router)
})

在这里插入图片描述
我们可以看到路由的所有方法都会在这里体现

console.log(Router.currentRoute._value) // 获取当前路由信息
console.log(Router.currentRoute._value.query) // 获取 ? 后传入的参数
console.log(Router.currentRoute._value.params) // 获取 :路径配置的参数 同 Vue2
Router.push('/home') // 路由跳转
Router.go(-1) // 路由回退
console.log(Router.options) // 获取所有路由的配置信息,如果你设置了动态路由但是并没有 push 到 options 里的话,这里是获取不到的

Vue3 篇幅完结之后我们会上传相对应的免费源码,以供二次开发的使用

猜你喜欢

转载自blog.csdn.net/Web_chicken/article/details/128608837