全局前置守卫
- 可以使用 router.beforeEach 注册一个全局前置守卫
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
// ...
})
to: Route: 即将要进入的目标路由
from: Route: 当前导航正要离开的路由
next:类似于中间件的拦截器
案例分析
全局前置守卫模拟登录鉴权案例
<style>
html {
overflow-x: hidden;
height: 1500px;
}
.router-link-active {
background: rgb(29, 109, 29);
}
h1 {
color: cornflowerblue;
}
.ani-enter {
transform: translateX(-100%);
opacity: 0;
}
.ani-enter-active,
.ani-leave-active {
transition: all .5s;
}
.ani-leave-to {
transform: translateX(100%);
opacity: 0;
}
</style>
</head>
<body>
<div id="app">
<router-link tag="button" to="/home">home页</router-link>
<router-link tag="button" to="/news">新闻页</router-link>
<router-link tag="button" to="/mine">个人中心</router-link>
<!-- <button @click='enterHome'>主页</button>
<button @click='enterNews'>新闻</button>
<button @click='enterMine'>我的中心</button> -->
<!-- 出口 -->
<!-- 过度动画可以将出口用transition包裹 -->
<transition name="ani" mode="out-in">
<router-view></router-view>
</transition>
</div>
</body>
<script src="./js/vue.js"></script>
<script src="./js/vue-router.js"></script>
<script>
//定义组件
let Home = {
template: `
<div>
<h2>Home</h2>
</div>
`
}
let News = {
template: `
<div>
<h2>News</h2>
</div>
`
}
let Mine = {
template: `
<div>
<h2>Mine</h2>
</div>
`
}
//来个登录组件
let Login = {
template: `
<div>
<h1>登录页</h1>
<button @click="login">登录</button>
</div>
`,
methods: {
login() {
//设置个本地存储,再去前置守卫进行登录判断
localStorage.setItem('access_token', 'blackLetter');
console.log(this.$route);
if (this.$route.params.from) {
this.$router.push(this.$route.params.from)
} else {
this.$router.push('/home')
}
}
}
}
const routes = [
{
path: "/",
redirect: '/home',
},
{
path: '/login',
name: 'login',
component: Login,
meta: {
}
},
{
path: '/home',
name: 'home',
component: Home,
//meta标签可以自定义参数,路由元信息
meta: {
needLogin: false
}
},
{
path: '/news',
name: 'news',
component: News,
//meta标签可以自定义参数,路由元信息
meta: {
needLogin: false
}
},
{
path: '/mine',
name: 'mine',
component: Mine,
meta: {
needLogin: true
}
},
]
//路由实例化
const router = new VueRouter({
routes,
mode:'hash',
scrollBehavior(to, from, savedPosition) {
console.log(savedPosition);
if (savedPosition) {
return savedPosition
} else {
return { x: 0, y: 0 }
}
}
})
//定义全局前置守卫
router.beforeEach((to, from, next) => {
// to 去哪 next 类似于中间件,拦截的关键,也可以带参数
console.log(to);
// console.log(from);
/*
1.通过判断to.fullPath来判断是否去登录注册页,是就放行
2.通过判断有没有本地存储来决定是否放行
*/
console.log(to.meta.needLogin)
if (to.fullPath === '/login' || to.fullPath === '/register') {
next()
} else {
//判断是否需要登录 ,不需要就放行,路由中有设置meta属性
if (to.meta.needLogin) {
let access_token = localStorage.getItem('access_token');
if (access_token) {
next();
} else {
// next('/login')
// console.log(to.fullPath);
next({
name: 'login',
//通过传自定义参数来判断重定向到登录页时的页面信息
params: {
// 比如去个人中心被重定向到登录,获取到了即将前往的路径
//登陆完成可以直接跳转到对应页面
from: to.fullPath
}
})
}
} else {
next()
}
}
})
//全局后置守卫
router.afterEach((to, from) => {
// ...
})
let vm = new Vue({
el: '#app',
router,
methods: {
// enterHome() {
// this.$router.push('/home')
// },
// enterNews() {
// this.$router.push({ name: 'news' })
// },
// enterMine() {
// this.$router.push('/mine')
// },
}
})
</script>
全局后置守卫(没有next参数,因为没有拦截功能)
router.afterEach((to,from)=>{
})
路由独享的守卫
- 可以在上直接定义 beforeEnter 守卫
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
组件内的守卫
- 可以在内直接定义以下路由导航守卫
const Foo = {
template: `...`,
beforeRouteEnter (to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
},
beforeRouteUpdate (to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave (to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
}
路由元信息
- 定义路由的时候可以配置 meta 字段
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
children: [
{
path: 'bar',
component: Bar,
// a meta field
meta: { requiresAuth: true }
}
]
}
]
})
过渡动效
- <router-view> 是基本的动态组件,所以我们可以用 <transition> 组件给它添加一些过渡效果
<transition name="xxx" mode="out-in">
<router-view></router-view>
</transition>