概述
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