路由组件传参
通过props解耦
const User = { props: ['id'], template: '<div>User {{ id }}</div>' } const router = new VueRouter({ routes: [ { path: '/user/:id', component: User, props: true }, // 对于包含命名视图的路由,你必须分别为每个命名视图添加 `props` 选项: { path: '/user/:id', components: { default: User, sidebar: Sidebar }, props: { default: true, sidebar: false } } ] })
布尔模式
如果props被设置为true,route.params参数将被设置为组件属性
对象模式
const router = new VueRouter({ routes: [ { path: '/promotion/from-newsletter', component: Promotion, props: { newsletterPopup: false } } ] })
函数模式
/search?q=vue 会将{query:vue}传递给组件SearchUser
const router = new VueRouter({ routes: [ { path: '/search', component: SearchUser, props: (route) => ({ query: route.query.q }) } ] })
History模式
vue-router默认使用hash模式
const router = new VueRouter({ mode: 'history', routes: [...] })
如果使用history模式,URL就像正常url,http://mysite.com/user/id
这种模式需要后台配置
警告:所有路径都会返回index.html,因此需要配置一个404页面
const router = new VueRouter({ mode: 'history', routes: [ { path: '*', component: NotFoundComponent } ] })
导航守卫
全局前置守卫
const router = new VueRouter({ ... }) router.beforeEach((to, from, next) => { // ... })
三个参数
to:即将进入的Route
from:当前导航离开的Route
next:
next()进行管道中的下一个钩子
next(false)中断当前导航
next('/')或next({path:'/'}) 中断当前导航,跳转到下一个导航
一个登陆案例,根据用户是否登录判断路由跳转
router.beforeEach((to, from, next) => { // 如果不是登录页 if (to.name !== 'login') { if (HAS_LOGIN) next() else next({ name: 'login' }) } else { if (HAS_LOGIN) next({ name: 'home' }) else next() } })
全局后置钩子
router.afterEach((to, from) => { // ... })
一个页面加载的案例。loading设置
路由独享守卫
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` } }
完整的导航流出
https://router.vuejs.org/zh/guide/advanced/navigation-guards.html#组件内的守卫
路由元信息
定义路由可以配置meta字段
const router = new VueRouter({ routes: [ { path: '/foo', component: Foo, children: [ { path: 'bar', component: Bar, // a meta field meta: { requiresAuth: true } } ] } ] })
我们在全局导航守卫中调用
case
router.beforeEach((to, from, next) => { console.log(to) })
fullPath: "/foo/bar" hash: "" matched: (2) [{…}, {…}] meta: {requireAuth: true} name: "bar" params: {} path: "/foo/bar" query: {} __proto__: Object
我们能从to中获得meta中数据
router.beforeEach((to, from, next) => { const requireAuth = to.meta.requireAuth if (requireAuth) { if (HAS_LOGIN) next() else next({ 'name': 'login' }) } 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> ` }
数据获取
导航完成后获取数据
$router.params.id获得文章数据
<template> <div class="post"> <div class="loading" v-if="loading"> Loading... </div> <div v-if="error" class="error"> {{ error }} </div> <div v-if="post" class="content"> <h2>{{ post.title }}</h2> <p>{{ post.body }}</p> </div> </div> </template>
export default { data () { return { loading: false, post: null, error: null } }, created () { // 组件创建完后获取数据, // 此时 data 已经被 observed 了 this.fetchData() }, watch: { // 如果路由有变化,会再次执行该方法 '$route': 'fetchData' }, methods: { fetchData () { this.error = this.post = null this.loading = true // replace getPost with your data fetching util / API wrapper getPost(this.$route.params.id, (err, post) => { this.loading = false if (err) { this.error = err.toString() } else { this.post = post } }) } } }
在导航完成前获得数据beforeRouterEnter
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 } } } }
滚动行为
const router = new VueRouter({ routes: [...], scrollBehavior (to, from, savedPosition) { // return 期望滚动到哪个的位置 } })
当切换到新的路由时候,想要页面滚动到顶部,或者原先的位置
scrollBehavior (to, from, savedPosition) { return { x: 0, y: 0 } }
路由懒加载
const Foo = () => import('./Foo.vue')
const router = new VueRouter({ routes: [ { path: '/foo', component: Foo } ] })