导航守卫
官方解释:
vue-router
提供的导航守卫主要用来通过跳转或取消的方式守卫导航。有多种机会植入路由导航过程中:全局的, 单个路由独享的, 或者组件级的。
全局守卫:
router.enterEach((to,from,next)>={
})
to: Route
: 即将要进入的目标路由对象
对应参数
fullPath:"/foo" hash:"" matched:[] meta:{} name:null params: __proto__:Object path:"/foo" query:{}
from: Route
: 当前导航正要离开的路由 (可以当成重定向使用)
ƒunction redirect(location) { return _this2.push(location); }
next: Function
: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next
方法的调用参数。
next()
: 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。
next(false)
: 中断当前的导航。如果浏览器的 URL 改变了(可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from
路由对应的地址。
next('/')
或者 next({ path: '/' })
: 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。
next(error)
: (2.4.0+) 如果传入 next
的参数是一个 Error
实例,则导航会被终止且该错误会被传递给 router.onError()
注册过的回调。
<template> <div> <h2>About</h2> </div> </template>
components/Dashboard.vue
<template> <div> <h2>Dashboard</h2> <p>Yay you made it!</p> </div> </template>
components/login.vue
<template> <div> <h2>login</h2> </div> </template>
app.js
import Vue from 'vue' import VueRouter from 'vue-router' Vue.use(VueRouter) import About from './components/About.vue' import Dashboard from './components/Dashboard.vue' import Login from './components/Login.vue' const router = new VueRouter({ mode: 'history', base: __dirname, routes: [ { path: '/about', component: About }, { path: '/dashboard', component: Dashboard }, { path: '/login', component: Login,name:'Login' } ] }) router.beforeEach((to, from, next) => { const islogin=false console.log(to.path) console.log(!islogin&&to.path=='/login') if(!islogin&&to.path=='/login'){ next(); }else{ from({path:'login'}) } }) var vm=new Vue({ router, template: ` <div id="app"> <h1>Navigation Guards</h1> <ul> <li><router-link to="/">/</router-link></li> <li><router-link to="/about">/about</router-link></li> <li><router-link to="/dashboard">/dashboard</router-link></li> <li><router-link to="/login">/dashboard</router-link></li> </ul> <router-view class="view"></router-view> </div>
`
}).$mount('#app')
上图实现的直接链接判断是否登入时,未登录的情况下直接跳转到登录页
路由独享的守卫
你可以在路由配置上直接定义 beforeEnter
守卫:
const router = new VueRouter({ routes: [ { path: '/foo', component: Foo, beforeEnter: (to, from, next) => { // ... } } ] })
举个例子
注意小组件如上面一个例子
import Vue from 'vue' import VueRouter from 'vue-router' Vue.use(VueRouter) import auth from './auth' import App from './components/App.vue' import About from './components/About.vue' import Dashboard from './components/Dashboard.vue' import Login from './components/Login.vue' function requireAuth (route, redirect, next) { if (!auth.loggedIn()) { next({ path: '/login', query: { redirect: route.fullPath } }) } else { next() } } const router = new VueRouter({ mode: 'history', base: __dirname, routes: [ { path: '/about', component: About, beforeEnter: function (to, from) { const login = false if (!login) {
alert('111') from('/login') } } }, { path: '/dashboard', component: Dashboard }, { path: '/login', component: Login,name:'Login'} ] }) var vm=new Vue({ router, template: ` <div id="app"> <h1>Navigation Guards</h1> <ul> <li><router-link to="/">/</router-link></li> <li><router-link to="/about">/about</router-link></li> <li><router-link to="/dashboard">/dashboard</router-link></li> </ul> <router-view class="view"></router-view> </div> ` }).$mount('#app')
具体实现的效果
组件内的守卫
beforeRouteEnter beforeRouteEnter beforeRouteLeave
官方模板
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` } }
举个例子1:
其他的组件的写法跟第一个一样的
beforeRouteEnter
// 在渲染该组件的对应路由被 confirm 前调用 // 不!能!获取组件实例 `this` 因为当守卫执行前,组件实例还没被创建,路由也不会改变
所以有写next()时,组件是不会展示的
about.vue
<template> <div> <h2>About</h2> <p>Yay you made it!</p> <div>{{num}}</div> </div> </template> <script> export default { data(){ return { num: 18 } }, beforeRouteEnter(to, from, next){ console.log(to.path) }, beforeRouteLeave (to, from, next){ console.log(to.path); } } </script>
import Vue from 'vue' import VueRouter from 'vue-router' Vue.use(VueRouter) import auth from './auth' import About from './components/About.vue' import Dashboard from './components/Dashboard.vue' import Login from './components/Login.vue' function requireAuth (route, redirect, next) { if (!auth.loggedIn()) { next({ path: '/login', query: { redirect: route.fullPath } }) } else { next() } } const router = new VueRouter({ mode: 'history', base: __dirname, routes: [ {path: '/about', component: About}, { path: '/dashboard', component: Dashboard }, { path: '/login', component: Login,name:'Login'} ] }) var vm=new Vue({ router, template: ` <div id="app"> <h1>Navigation Guards</h1> <ul> <li><router-link to="/">/</router-link></li> <li><router-link to="/about">/about</router-link></li> <li><router-link to="/dashboard">/dashboard</router-link></li> </ul> <router-view class="view"></router-view> </div> ` }).$mount('#app')
实际实现效果:
举个例子2:
其他的组件的写法跟第一个一样的
components/About.vue
<template> <div> <h2>About</h2> <p>Yay you made it!</p> <div>{{num}}</div> </div> </template> <script> export default { data(){ return { num: 18 } }, beforeRouteEnter(to, from, next){ console.log(to.path) next(vm=>{ vm.num=19; }) }, beforeRouteLeave (to, from, next){ console.log(to.path) } } </script>
import Vue from 'vue' import VueRouter from 'vue-router' Vue.use(VueRouter) import auth from './auth' import About from './components/About.vue' import Dashboard from './components/Dashboard.vue' import Login from './components/Login.vue' function requireAuth (route, redirect, next) { if (!auth.loggedIn()) { next({ path: '/login', query: { redirect: route.fullPath } }) } else { next() } } const router = new VueRouter({ mode: 'history', base: __dirname, routes: [ {path: '/about', component: About}, { path: '/dashboard', component: Dashboard }, { path: '/login', component: Login,name:'Login'} ] }) var vm=new Vue({ router, template: ` <div id="app"> <h1>Navigation Guards</h1> <ul> <li><router-link to="/">/</router-link></li> <li><router-link to="/about">/about</router-link></li> <li><router-link to="/dashboard">/dashboard</router-link></li> </ul> <router-view class="view"></router-view> </div> ` }).$mount('#app')
实现效果:dashboard地址时,导航栏平没有发生变化,并不会离开
这里注意当我点击
如果想要离开的话,about.vue 这样改:只要在beforeRouteLeave在加入next()
<template> <div> <h2>About</h2> <p>Yay you made it!</p> <div>{{num}}</div> </div> </template> <script> export default { data(){ return { num: 18 } }, beforeRouteEnter(to, from, next){ console.log(to.path) next(vm=>{ vm.num=19; }) }, beforeRouteLeave (to, from, next){ console.log(to.path); next(); } } </script>