Vue-router:10、路由守卫
Vue-router
中的路由守卫,主要是对其内容进行保护,如果没有对应的权限,则不允许访问。
我们首先来看一下全局守卫,也就是所有的路由都会经过全局守卫来进行检测。
//实现全局守卫
router.beforeEach((to, from, next) => {
//to:去哪个页面,from来自哪个页面,next继续执行.
//判断哪个路由需要进行守卫,这里可以通过元数据方式
if (to.meta.auth) {
if (window.isLogin) {
next();
} else {
next("/login?redirect=" + to.fullPath);
}
} else {
next();
}
});
在上面的代码中,创建了路由守卫,但是需要判断的是需要对哪个路由进行守卫,这里就是通过元数据来进行判断的。如果所跳转到的路由有元数据,并且对应的auth
属性为true
表明是需要进行守卫的,那么下面就需要校验用户是否登录,这里是通过判断否window.isLogin
的值是否为true
来进行判断的(这里简化了操作,实际应用中应该存储到sessionStorage
),如果条件成立则表明用户登录,就继续访问用户希望访问到的页面,否则跳转到登录页面,而且将用户希望访问的页面地址也传递到了登录页面,这样用户登录成功后,可以直接跳转到要访问的页面。
如果没有元数据,则继续访问用户要访问的页面。
// 创建路由对象
const router = new VueRouter({
routes: [
{ path: "/login", component: Login },
{
path: "/",
component: App,
redirect: "/users",
children: [
{
path: "/users",
component: Users,
meta: {
auth: true,
},
},
{ path: "/userinfo/:id", component: UserInfo, props: true },
{ path: "/rights", component: Rights },
{ path: "/goods", component: Goods },
{ path: "/orders", component: Orders },
{ path: "/settings", component: Settings },
],
},
],
});
在上面的代码中,给/users
路由添加了元数据。
登录组件创建如下:
const Login = {
data() {
return {
isLogin: window.isLogin,
};
},
template: `<div>
<button @click="login" v-if="!isLogin">登录</button>
<button @click="logout" v-else>注销</button>
</div>`,
methods: {
login() {
window.isLogin = true;
this.$router.push(this.$route.query.redirect);
},
logout() {
this.isLogin = window.isLogin = false;
},
},
};
当单击登录按钮后,进行将window.isLogin
设置为true
, 并且进行跳转。
全部代码如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>基于vue-router的案例</title>
<script src="./lib/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<style type="text/css">
html,
body,
#app {
margin: 0;
padding: 0px;
height: 100%;
}
.header {
height: 50px;
background-color: #545c64;
line-height: 50px;
text-align: center;
font-size: 24px;
color: #fff;
}
.footer {
height: 40px;
line-height: 40px;
background-color: #888;
position: absolute;
bottom: 0;
width: 100%;
text-align: center;
color: #fff;
}
.main {
display: flex;
position: absolute;
top: 50px;
bottom: 40px;
width: 100%;
}
.content {
flex: 1;
text-align: center;
height: 100%;
}
.left {
flex: 0 0 20%;
background-color: #545c64;
}
.left a {
color: white;
text-decoration: none;
}
.right {
margin: 5px;
}
.btns {
width: 100%;
height: 35px;
line-height: 35px;
background-color: #f5f5f5;
text-align: left;
padding-left: 10px;
box-sizing: border-box;
}
button {
height: 30px;
background-color: #ecf5ff;
border: 1px solid lightskyblue;
font-size: 12px;
padding: 0 20px;
}
.main-content {
margin-top: 10px;
}
ul {
margin: 0;
padding: 0;
list-style: none;
}
ul li {
height: 45px;
line-height: 45px;
background-color: #a0a0a0;
color: #fff;
cursor: pointer;
border-bottom: 1px solid #fff;
}
table {
width: 100%;
border-collapse: collapse;
}
td,
th {
border: 1px solid #eee;
line-height: 35px;
font-size: 12px;
}
th {
background-color: #ddd;
}
</style>
</head>
<body>
<div id="app"><router-view></router-view></div>
<script>
const App = {
template: `<div>
<!-- 头部区域 -->
<header class="header">传智后台管理系统</header>
<!-- 中间主体区域 -->
<div class="main">
<!-- 左侧菜单栏 -->
<div class="content left">
<ul>
<li><router-link to="/users"> 用户管理</router-link></li>
<li><router-link to="/rights"> 权限管理</router-link></li>
<li><router-link to="/goods"> 商品管理</router-link></li>
<li><router-link to="/orders"> 订单管理</router-link></li>
<li><router-link to="/settings"> 系统设置</router-link></li>
</ul>
</div>
<!-- 右侧内容区域 -->
<div class="content right"><div class="main-content"> <router-view /></div></div>
</div>
<!-- 尾部区域 -->
<footer class="footer">版权信息</footer>
</div>`,
};
const Users = {
data() {
return {
userlist: [
{ id: 1, name: "张三", age: 10 },
{ id: 2, name: "李四", age: 20 },
{ id: 3, name: "王五", age: 30 },
{ id: 4, name: "赵六", age: 40 },
],
};
},
methods: {
goDetail(id) {
console.log(id);
this.$router.push("/userinfo/" + id);
},
},
template: `<div>
<h3>用户管理区域</h3>
<table>
<thead>
<tr><th>编号</th><th>姓名</th><th>年龄</th><th>操作</th></tr>
</thead>
<tbody>
<tr v-for="item in userlist" :key="item.id">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.age}}</td>
<td>
<a href="javascript:;" @click="goDetail(item.id)">详情</a>
</td>
</tr>
</tbody>
</table>
</div>`,
};
//用户详情组件
const UserInfo = {
props: ["id"],
template: `<div>
<h5>用户详情页 --- 用户Id为:{{id}}</h5>
<button @click="goback()">后退</button>
</div>`,
methods: {
goback() {
// 实现后退功能
this.$router.go(-1);
},
},
};
const Rights = {
template: `<div>
<h3>权限管理区域</h3>
</div>`,
};
const Goods = {
template: `<div>
<h3>商品管理区域</h3>
</div>`,
};
const Orders = {
template: `<div>
<h3>订单管理区域</h3>
</div>`,
};
const Settings = {
template: `<div>
<h3>系统设置区域</h3>
</div>`,
};
const Login = {
data() {
return {
isLogin: window.isLogin,
};
},
template: `<div>
<button @click="login" v-if="!isLogin">登录</button>
<button @click="logout" v-else>注销</button>
</div>`,
methods: {
login() {
window.isLogin = true;
this.$router.push(this.$route.query.redirect);
},
logout() {
this.isLogin = window.isLogin = false;
},
},
};
// 创建路由对象
const router = new VueRouter({
routes: [
{ path: "/login", component: Login },
{
path: "/",
component: App,
redirect: "/users",
children: [
{
path: "/users",
component: Users,
meta: {
auth: true,
},
},
{ path: "/userinfo/:id", component: UserInfo, props: true },
{ path: "/rights", component: Rights },
{ path: "/goods", component: Goods },
{ path: "/orders", component: Orders },
{ path: "/settings", component: Settings },
],
},
],
});
//实现全局守卫
router.beforeEach((to, from, next) => {
//to:去哪个页面,from来自哪个页面,next继续执行.
//判断哪个路由需要进行守卫,这里可以通过元数据方式
if (to.meta.auth) {
if (window.isLogin) {
next();
} else {
next("/login?redirect=" + to.fullPath);
}
} else {
next();
}
});
const vm = new Vue({
el: "#app",
router,
});
</script>
</body>
</html>
以上是全局守卫,对所有的路由都起作用。
但是,如果项目比较简单,路由规则定义的比较少,可以将守卫定位到某个路由规则内。这就是路由独享守卫
// 创建路由对象
const router = new VueRouter({
routes: [
{ path: "/login", component: Login },
{
path: "/",
component: App,
redirect: "/users",
children: [
{
path: "/users",
component: Users,
meta: {
auth: true,
},
beforeEnter(to, from, next) {
if (window.isLogin) {
next();
} else {
next("/login?redirect=" + to.fullPath);
}
},
},
{ path: "/userinfo/:id", component: UserInfo, props: true },
{ path: "/rights", component: Rights },
{ path: "/goods", component: Goods },
{ path: "/orders", component: Orders },
{ path: "/settings", component: Settings },
],
},
],
});
在上面的代码中,给/users
这个路由守卫,注意这里的方法名为beforeEnter
.同时,这里将守卫定义在/users
路由规则内,所以不需要对元数据进行判断,只需要判断用户是否登录就可以了。(注意:在进行以上测试时,需要将全局守卫的代码注释掉)
组件内守卫
可以在路由组件内直接定义以下路由导航守卫。
beforeRouteEnter
beforeRouteUpdate
beforeRouteLeave
将如下的代码直接添加到组件内。
const Users = {
data() {
return {
userlist: [
{ id: 1, name: "张三", age: 10 },
{ id: 2, name: "李四", age: 20 },
{ id: 3, name: "王五", age: 30 },
{ id: 4, name: "赵六", age: 40 },
],
};
},
methods: {
goDetail(id) {
console.log(id);
this.$router.push("/userinfo/" + id);
},
},
template: `<div>
<h3>用户管理区域</h3>
<table>
<thead>
<tr><th>编号</th><th>姓名</th><th>年龄</th><th>操作</th></tr>
</thead>
<tbody>
<tr v-for="item in userlist" :key="item.id">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.age}}</td>
<td>
<a href="javascript:;" @click="goDetail(item.id)">详情</a>
</td>
</tr>
</tbody>
</table>
</div>`,
beforeRouteEnter(to, from, next) {
if (window.isLogin) {
next();
} else {
next("/login?redirect=" + to.fullPath);
}
},
};
在上面的代码中,直接将路由守卫对应的方法添加到了组件中。
注意:在测试之前将路由规则中定义的路由守卫的代码注释掉。