共计 4507 个字符,预计需要花费 12 分钟才能阅读完成。
一、导航守卫
残缺的导航解析流程:
- 导航被触发
- 在失活的组件里调用 beforeRouteLeave
- 调用全局的 beforeEach
- 在重用的组件里调用 beforeRouteUpdate
- 在路由配置里调用 beforeEnter
- 解析异步路由组件
- 在被激活的组件里调用 beforeRouteEnter
- 调用全局的 beforeResolve
- 导航被确认
- 调用全局的 afterEach
- 触发 DOM 更新
- 调用 beforeRouteEnter 守卫中传给 next 的回调函数,创立好的组件实例会作为回调函数的参数传入。
参数或查问的扭转并不会触发进入 / 来到的导航守卫。能够通过观察 $route 对象来应答这些变动,或应用 beforeRouteUpdate 的组件内守卫。
1、全局前置守卫
router.beforeEach
const router = new VueRouter({...})
router.beforeEach(to,from,next) => {
/*to:Route-- 行将要进入的指标路由对象 */
/*from:Route-- 以后导航正要来到的路由 */
/*next:function-- 必须要调用该办法来 resolve 这个钩子。执行成果依赖 next 办法的调用参数。*/
next() /* 进行管道中的下一个钩子,若全副执行完了,则导航的状态就是 confirmed。*/
next(false) /* 中断以后的导航。如果浏览器的 url 扭转了(可能是用户手动或浏览器后退),那么 url 会重置到 from 路由对应的地址。*/
next('/') /* 同下 */
next({path:'/'}) /* 跳转到一个不同的地址。*/
next(error) /* 导航被终止,且谬误会传递给 router.onError()注册过的回调。*/}
确保 next 函数在任何给定的导航守卫中都被严格调用一次。可呈现多于一次,但只能在所有的逻辑门路都不重叠的状况下,否则钩子永远都不会被解析或报错。
/* BAD */
router.beforeEach((to, from, next) => {if (to.name !== 'Login' && !isAuthenticated) next({name: 'Login'})
/* 如果用户未能验证身份,则 `next` 会被调用两次 */
next()})
/* GOOD */
router.beforeEach((to, from, next) => {if (to.name !== 'Login' && !isAuthenticated) next({name: 'Login'})
else next()})
2、全局解析守卫
router.beforeResolve– 与 router.beforeEachj 相似,区别为:在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用。
3、全局后置钩子
router.afterEach()– 无 next(), 也不会扭转导航自身
router.afterEach(to,from)=>{//...}
路由配置形式:
1、路由独享的守卫 – 间接在路由配置上定义 beforeEnter 守卫
const router = new VueRouter({
routes: [
{
path: '/user',
component: User,
beforeEnter: (to,from,next)=>{}}
]
})
2、组件内的守卫
能够在路由组件内间接定义以下路由导航守卫
beforeRouteEnter
beforeRouteUpdate
beforeRouteLeave
const Foo = {
template: `...`,
beforeRouteEnter(to, from, next) {
/* 在渲染该组件的对应路由被 confirm 前调用 */
/* 不能!获取组件实例 `this`*/
/* 因为当守卫执行前,组件实例还没被创立, 能够通过传一个回调给 next 来拜访组件实例,仅该守卫反对此办法 */
next(vm => {/* 通过 vm 拜访组件实例 */})
},
beforeRouteUpdate(to, from, next) {
/* 在以后路由扭转,然而该组件被复用时调用 */
/* 举例来说,对于一个带有动静参数的门路 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候 */
/* 因为会渲染同样的 Foo 组件,因而组件实例会被复用。而这个钩子就会在这个状况下被调用。*/
/* 能够拜访组件实例 `this`*/
this.name = to.params.name
next()},
beforeRouteLeave(to, from, next) {
/* 导航来到该组件的对应路由时调用 */
/* 能够拜访组件实例 `this`*/
/* 该守卫能够用来禁止用户在还未保留批改前忽然来到,导航能够通过 next(false)勾销 */
const answer = window.confirm('还没有保留,确定要来到吗')
if(answer){next()
}else{next(false)
}
}
}
二、路由元信息 -meta
路由登录拦挡
/*1、在须要做登录验证的路由中设置 meta*/
requireAuth 值为 true
const router = new VueRouter({
routes = [
{
path: '/detail',
name: 'detail',
component: Detail,
meta: {requireAuth: true}
},
{
path: '/login',
name: 'login',
component: Login
}
]
})
/*2、router.beforeEach()钩子函数,会在进入每个网页之前被调用,可在该钩子函数内做路由拦挡 */
router.beforeEach((to,from,next) => {
/* 判断将进入的路由是否须要路由拦挡 */
if(to.matched.some(record => record.meta.requireAuth){
/*vuex.state 判断 token 是否存在 */
if(store.state.token){
/* 已登录 */
next()}else{
next({
path: '/login',
query: {redirect: to.fullPath}
})
}
} else {next()
}
})
三、过渡动效
应用 <transition> 标签将 <router-view> 标签包裹能够增加一些过渡成果,会给在这个 router-view 中的路由都加上同一种成果。
若想给不同的路由加不同的成果,能够在路由组件中设置 <transition> 增加成果
const Foo = {
template: `
<transition name="slide">
<div class="foo">...</div>
</transition>
`
}
const Bar = {
template: `
<transition name="fade">
<div class="bar">...</div>
</transition>
`
}
设置动静过渡
<!-- 应用动静的 transition name -->
<transition :name="transitionName">
<router-view></router-view>
</transition>
//...
// 接着在父组件内
// watch $route 决定应用哪种过渡
watch: {'$route' (to, from) {const toDepth = to.path.split('/').length
const fromDepth = from.path.split('/').length
this.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left'
}
}
四、数据获取
在进入某个路由后,须要从服务器获取数据,有两种形式:
1、导航实现之后获取:
在路由组件的 created 钩子函数中调用获取数据的办法
export default{data (){
return {loading: false}
},
created(){
// 组件创立实现后获取数据,此时 data 曾经被 observed 了
this.fetchData()},
methods: {fetchData() {
this.loading = true
// 发动数据申请,此时能够通过 $route.params 获取 url 上的数据
getPost(this.$route.params.id,(res)=>{//...})
}
}
}
2、在导航前获取数据
在要跳转的路由组件中的 beforeRouteEnter 守卫中获取数据,当数据获取胜利后只调用 next()办法。
export default {data () {
return {
post: null,
error: null
}
},
beforeRouteEnter (to, from, next) {getPost(to.params.id, (err, post) => {next(vm => vm.setData(err, post))
})
},
// 路由扭转前,组件就曾经渲染完了
// 逻辑稍稍不同
beforeRouteUpdate (to, from, next) {
this.post = null
getPost(to.params.id, (err, post) => {this.setData(err, post)
next()})
},
methods: {setData (err, post) {if (err) {this.error = err.toString()
} else {this.post = post}
}
}
}
五、滚动行为
当切换到新路由时,页面滚动到顶部或放弃原先的滚动地位,能够在 router 实例中提供一个 scrollBehavior 办法。
const router = new VueRouter({routes: [...],
scrollBehavior(to,from,savedPosition){
//return 冀望滚动到的地位
//return {x: number, y: number}
// 滚动到顶部
//return {x:0,y:0}
//savedPosition 在按下后退和后退按钮时可用
if(savedPosition) {return savedPosition} else {return {x:0,y:0}
}
}
})
模仿滚动到锚点
scrollBehavior(to,from,savedPosition){if(to.hash) {
return {
selector: to.hash,
// 设置平滑滚动
behavior: 'smooth'
}
}
}
六、路由懒加载
为进步加载效率,应用懒加载,让路由被拜访时才加载对应组件。需联合 Vue 异步组件和 webpack
//1、将异步组件定义为返回一个 promise 的工厂函数。const Foo = ()=>{
Promise.resolve({// 组件定义对象})
}
//2、应用 import 引入组件
import('./Foo.vue') //import 返回一个 promise
// 可联合两者
const Foo = ()=> import('./Foo.vue')
// 路由在实例化时跟一般的一样