概述
Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。包含的功能有:
- 嵌套的路由/视图表
- 模块化的、基于组件的路由配置
- 路由参数、查询、通配符
- 基于 Vue.js 过渡系统的视图过渡效果
- 细粒度的导航控制
- 带有自动激活的 CSS class 的链接
- HTML5 历史模式或 hash 模式,在 IE9 中自动降级
- 自定义的滚动条行为
安装
vue-router 是一个插件包,所以我们还是需要用 npm/cnpm 来进行安装的。打开命令行工具,进入你的项目目录,输入下面命令。
npm install vue-router --save-dev //安装在开发环境 npm install --save vue-router //安装在生成环境
如果在一个模块化工程中使用它,必须要通过 Vue.use()
明确地安装路由功能:
import Vue from 'vue' import VueRouter from 'vue-router' Vue.use(VueRouter);
使用
以下案例在 vue-cli 项目中使用 vue-router
创建组件页面
创建一个名为 src/components
的目录专门放置我们开发的 Vue 组件,在 src/components
目录下创建一个名为 Content.vue
的组件,代码如下:
注意<template></template>中必须有一个<div/>,否则会报错
<template> <div> 我是内容页 </div> </template> <script> export default { name: "Content" } </script> <style> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>
安装路由
创建一个名为 src/router
的目录专门放置我们的路由配置代码,在 src/router
目录下创建一个名为 index.js
路由配置文件,代码如下:
import Vue from 'vue' // 导入路由插件 import Router from 'vue-router' // 导入上面定义的组件 import Content from '@/components/Content' // 安装路由 Vue.use(Router); // 配置路由 export default new Router({ routes: [ { // 路由路径 path: '/content', // 路由名称 name: 'Content', // 跳转到组件 component: Content } ] });
配置路由
修改 main.js
入口文件,增加配置路由的相关代码
import Vue from 'vue' import App from './App' // 导入上面创建的路由配置目录 import router from './router' Vue.config.productionTip = false; new Vue({ el: '#app', // 配置路由 router, components: { App }, template: '<App/>' });
使用路由
修改 App.vue
组件,代码如下:
<template> <div id="app"> <router-link to="/">首页</router-link> <router-link to="/content">内容</router-link> <router-view></router-view> //路由组件展示的地方 </div> </template> <script> export default { name: 'App' } </script> <style> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>
说明:
- router-link: 默认会被渲染成一个
<a>
标签,to
属性为指定链接 - router-view: 用于渲染路由匹配到的组件
效果演示
访问:localhost:8080/#/content
权限管理
由于我们菜单栏是通过roles自动生成的,所以我们第一步,根据不同的用户返回不同的菜单(不能解决用户直接输入网址访问)
1、给router设置属性,比如在mete中添加一个roles
{ path: "/", name: "dashboard", hidden: true, component: Layout, redirect: "/home", //父路由没有在mete中设置roles,表示任何人都可以访问 children: [ { path: "/home", name: "home", meta: {title: '首页', icon: 'fa fa-home',roles:["admin","xx"]}, //子路由设置了roles,表示只有admin和xx可以访问 component: () => import("@/views/Home.vue") } ] },
2、当用户登录的时候,保存user的时候,我们遍历routes中的每一个route,判断该路由时候被过滤掉(在actions.js中设置)
import {routes} from "@/router"; import {ActionTree} from 'vuex'; import jwt_decode from 'jwt-decode'; const actions: ActionTree<any, any> = { async setUser({state, commit}, user: any) { var jwtDecode:any = jwt_decode(user); //设置user信息 commit('SET_USER', jwtDecode); //----------------设置用户访问路由的权限--------------------- //获取jwtDecode中的user_roles,user信息中需要有user_roles(后台返回的) const { user_roles } = jwtDecode; //过滤路由(routes:当前的所有的路由) let accessedRouters = filterAsyncRouter(routes,user_roles); commit('SET_ROUTERS', accessedRouters); } } /** * 递归对routers进行过滤,返回routers * route:当前路由对象 */ function filterAsyncRouter(asyncRouterMap: Array<any>,roles:any) { const accessedRouters = asyncRouterMap.filter(route => { if (hasPermission(roles,route)) { if (route.children && route.children.length) { route.children = filterAsyncRouter(route.children,roles); } return true; } return false; }); return accessedRouters; } /** * 判断是否有权限 * @param roles 当前角色 * @param route 当前路由对象 * */ function hasPermission(roles: any, route: any) { if (route.meta && route.meta.roles) { //roles是自己设置的一个数组 return route.meta.roles.some((role: string) => role.indexOf(roles) >= 0) }else { //如果当前路由对象routes.meta没有roles属性,表示任何人都可以访问路由 return true; } } export default actions;
解决用户直接输入网址访问的问题
import jwt_decode from 'jwt-decode'; router.beforeEach((to, form, next) => { //拦截上面配置的路由 // 获取用户登录状态 var isLogin = localStorage.getItem("token") != null ? true : false; // 注销 if (to.path == '/logout') { // 清空 localStorage.clear() // 跳转到登录 next({path: '/login'}); } if (to.path != '/login' && to.path != '/password') { //如果没有登录 if (isLogin == false) { next({path: '/login'}); } //如果已经登录,判断是否具有访问该路由的资格 else { const decoded: any=jwt_decode(localStorage. tsToken); const { user_roles }=decoded; // @ts-ignore if (hasPermission(user_roles,to)) { next(); } else { next('/404'); // 没有权限进入 } } } // 下一个路由 next(); }); function hasPermission(roles: any, route: any) { if (route.meta && route.meta.roles) { //roles是自己设置的一个数组 return route.meta.roles.some((role: string) => role.indexOf(roles) >= 0) }else { //如果当前路由对象routes.meta没有roles属性,表示任何人都可以访问路由 return true; } } export default router