Vue Router高级

路由组件传参

通过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 }
  ]
})
原文地址:https://www.cnblogs.com/sonwrain/p/10806166.html