在第三篇中,我们主要学习了
组件的封装与使用
以及组件间传值
和Element Plus
表格、表单的用法
本期需要掌握的知识如下:
mixin
公共方法封装和使用VueRouter
VueRouter
完成 路由跳转
、获取路由信息
VueRouter
模块化、路由拦截器权限路由
配置下期需要掌握的知识如下:
Pinia
Pinia
完成登录存储用户信息
,并在页面使用/调用 Pinia
方法/数据Pinia
数据路由拦截
中使用 Pinia
代替 本地存储 Stroage
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()
}
使用 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') {// 获取 tokenlet apiToken = getlocalstroage('user') ? JSON.parse(getlocalstroage('user')) : nullif (!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
注意此处有大坑
/
,否则解析不成功router.options.routes.push
添加进去,否则在页面使用获取不到动态路由信息router.addRoute()
方法使用后必须 next({ ...to, replace: true })
,否则刷新后动态路由消失{ path: '/:pathMatch(.*)*', redirect: '/404' }
必须在最后添加该路由,否则匹配不到此路由后的路由// 最简单的方法 在需要的页面导入 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 篇幅完结之后我们会上传相对应的免费源码,以供二次开发的使用