在第三篇中,我们主要学习了
组件的封装与使用
以及组件间传值
和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
注意此处有大坑
- Vue3 中的 嵌套路由前不能携带
/
,否则解析不成功 - 动态设置的路由必须
router.options.routes.push
添加进去,否则在页面使用获取不到动态路由信息 router.addRoute()
方法使用后必须next({ ...to, replace: true })
,否则刷新后动态路由消失{ 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 篇幅完结之后我们会上传相对应的免费源码,以供二次开发的使用