vue项目实战(九):meta+导航守卫-权限控制:实现页面强制登陆
文章目录
在(七)中学了vue-route的基本使用,当然vue-route的功能不止于此,在这里我结合vue-route的导航守卫和route对象中的meta对象,来提供一个跳转时强行转入登陆页面的功能。
一、导航守卫简介
正如其名,vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航(对锚点的改变非常敏感)。有多种机会植入路由导航过程中:全局的, 单个路由独享的, 或者组件级的。参数或查询的改变并不会触发进入/离开的导航守卫。简单来说,就是对每个路由的变化,我们定义的一系列动作。
1-全局前置守卫:
以下代码可以创建一个前置守卫,我们先创建一个VueRouter
对象,然后通过实例化的VueRouter
对象创建一个前置守卫。
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
// ...
})
参数:
每个守卫方法接收三个参数:
-
to: Route
: 即将要进入的目标 路由对象 -
from: Route
: 当前导航正要离开的路由 -
next: Function
: !一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。
2-路由独享的守卫
直接在router实例化对象的routes列表中,在每个路由的后面进行定义
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
3-路由守卫的调用时机
- 导航被触发。
- 在失活的组件里调用离开守卫。
- 调用全局的
beforeEach
守卫。 - 在重用的组件里调用
beforeRouteUpdate
守卫 。 - 在路由配置里调用
beforeEnter
。 - 解析异步路由组件。
- 在被**的组件里调用
beforeRouteEnter
。 - 调用全局的
beforeResolve
守卫。 - 导航被确认。
- 调用全局的
afterEach
钩子。 - 触发 DOM 更新。
- 用创建好的实例调用
beforeRouteEnter
守卫中传给 next 的回调函数。
4-tips
一定一定一定要调用next函数,不然就卡住了。
5-示例
二、meta+导航守卫实现权限控制
我们使用三个页面,一个按钮来简单实现页面强制登陆登陆的功能。前端的逻辑大概是这样的:我们在首页显示:首页-博客两个按钮,点击首页显示”这里是首页“字样,点击博客强制跳转到登陆页面(如果没有登陆的话),登陆之后跳转到博客页面,此时显示退出按钮,退出后返回首页,再次进入博客需要重新进行登陆。
1-HTML元素定义
这是首页要显示的内容,这个button我们只有登陆了才会进行显示,因此使用v-show和一个变量连接起来,方便我们进行控制。
<div id="app">
<router-link to="/home">首页</router-link>
<router-link to="/blog">博客</router-link>
<button @click="exitHandler" v-show='isShow'>退出</button>
<router-view></router-view>
</div>
2-组件元素定义
我们有三个组件,分别是首页/博客/登陆页,比较复杂的是登陆页(先看代码,下文解释)
var Home={
template:`
<div>这里是首页</div>
`
};
var Blog={
template:`
<div>这里是博客</div>
`
};
var Login={
data(){
return{
name:"yfZhang",
password:"123456"
}
},
template:`
<div>
<input type='text' v-model='name'/>
<input type="text" v-model='password'/>
<input type="button" value='登陆'
@click="loginHandle()"/>
</div>
`,
methods:{
loginHandle(){
//登陆
vm.isShow = true;
localStorage.setItem("user", {name:this.name,
pwd:this.password});
//跳转到博客页面:编程式导航
this.$router.push({
name:"blog"
})
}
}
};
登陆页的组件其实就是维护了两个参数,两个文本框和一个button,然后绑定一个点击事件,每次点击登陆,我们将用户名与密码本地存储,然后使用编程式导航的方式进行页面跳转。这是导航的一种方式(使用this.$router.push({name : ''})
name对应的value是我们的其中一个路由的名字,该语句直接跳转到name
路由对应的地址)
3-router对象的定义-meta属性的添加
在创建router对象的时候,我们可以给一个router
对象添加meta
属性,用作未来的访问控制。也就是说每当我们跳转到对应的页面时,我们查询meta
中的auth
参数,如果他的值时true,那么我们直接跳转到登陆页面,而不是博客页面。
//创建router对象
var router = new VueRouter({
routes:[
{
path:"/home",
component: Home
},
{
path:"/blog",
name:"blog",
component:Blog,
//给未来的路由做权限控制
meta:{
//证明 用户访问该组件的时候需要登陆
auth:true
}
},
{
path:"/login",
component:Login
}
]
});
4-全局守卫实时监听
每次地址跳转的时候吗我们的全局守卫就会运行,我们先打印来源和目的地址,然后判断转向的页面是否要求必须登陆(meta
的auth
对象的值为true即必须登陆),多次点击博客我们会以本地存储是否有用户名密码为标准,有的话就是已经登陆过的,否则就转向登陆页面。当然如果去向页面根本没有这个要求,我们当然直接放行,next函数啥都不做。
router.beforeEach((to, from, next)=>{
console.log(to);
console.log(from);
if(to.meta.auth){
//用户点击了博客链接,需要登陆
if(localStorage.getItem('user')){
//本地存储不是空的,已经登陆了。
next();
}else{
next({
//
path:"/login"
})
}
}else{
//false直接放行,如果不调用可能会卡住页面
next();
}
next();
});
5-Vue实例对象掌控全局
Vue对象是不可缺少的一环,这里控制着退出键什么时候显示的参数isShow
,以及对退出按钮做出的相应。
vm = new Vue({
el:"#app",
data(){
return{
isShow: false
}
},
//交给Vue实例化对象管理
router,
methods:{
exitHandler(){
localStorage.removeItem('user');
vm.isShow=false;
this.$router.push({
name:"home"
})
}
}
})
6-完整代码
注意包的路径可能不太一杨
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>myVue</title>
<!--由于vue-router是依赖于vue的,所以两个包必须都引入,而且顺序必须是这样-->
<script type="text/javascript" src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript" src="./node_modules/vue-router/dist/vue-router.js"></script>
</head>
<body>
<div id="app">
<router-link to="/home">首页</router-link>
<router-link to="/blog">博客</router-link>
<button @click="exitHandler" v-show='isShow'>退出</button>
<router-view></router-view>
</div>
<script type="text/javascript">
var Home={
template:`
<div>这里是首页</div>
`
};
var Blog={
template:`
<div>这里是博客</div>
`
};
var Login={
data(){
return{
name:"yfZhang",
password:"123456"
}
},
template:`
<div>
<input type='text' v-model='name'/>
<input type="text" v-model='password'/>
<input type="button" value='登陆'
@click="loginHandle()"/>
</div>
`,
methods:{
loginHandle(){
//登陆
vm.isShow = true;
localStorage.setItem("user", {name:this.name,
pwd:this.password});
//跳转到博客页面:编程式导航
this.$router.push({
name:"blog"
})
}
}
};
//创建router对象
var router = new VueRouter({
routes:[
{
path:"/home",
name:"home",
component: Home
},
{
path:"/blog",
name:"blog",
component:Blog,
//给未来的路由做权限控制
meta:{
//证明 用户访问该组件的时候需要登陆
auth:true
}
},
{
path:"/login",
component:Login
}
]
});
router.beforeEach((to, from, next)=>{
console.log(to);
console.log(from);
if(to.meta.auth){
//用户点击了博客链接,需要登陆
if(localStorage.getItem('user')){
//本地存储不是空的,已经登陆了。
next();
}else{
next({
//
path:"/login"
})
}
}else{
//false直接放行,如果不调用可能会卡住页面
next();
}
next();
});
vm = new Vue({
el:"#app",
data(){
return{
isShow: false
}
},
//交给Vue实例化对象管理
router,
methods:{
exitHandler(){
localStorage.removeItem('user');
vm.isShow=false;
this.$router.push({
name:"home"
})
}
}
})
</script>
</body>
</html>
三、运行实例
1-开始页面
2-首页
3-博客页
4-登陆自动跳转
在这里你可以多次尝试首页/博客的转换,登陆状态不会改变。退出后返回首页,再点击博客就需要重新登陆了。