Vue Router高級

路由組件傳參html

經過props解耦vue

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 }
    }
  ]
})

布爾模式vue-router

若是props被設置爲true,route.params參數將被設置爲組件屬性app

對象模式ide

const router = new VueRouter({
  routes: [
    { path: '/promotion/from-newsletter', component: Promotion, props: { newsletterPopup: false } }
  ]
})

函數模式函數

/search?q=vue 會將{query:vue}傳遞給組件SearchUserpost

const router = new VueRouter({
  routes: [
    { path: '/search', component: SearchUser, props: (route) => ({ query: route.query.q }) }
  ]
})

History模式fetch

vue-router默認使用hash模式ui

const router = new VueRouter({
  mode: 'history',
  routes: [...]
})

若是使用history模式,URL就像正常url,http://mysite.com/user/idthis

這種模式須要後臺配置

警告:全部路徑都會返回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 }
  ]
})
相關文章
相關標籤/搜索