vue-route的用法

vue-router 兩種模式

SPA

單頁面應用,顧名思義,但也沒,加載頁面不會加載整個頁面,更新某個容器內內容,更新視圖不請求頁面,在vue中,vue-router用來實現

hash模式

先看官網介紹:

vue-router 默認 hash 模式 —— 使用 URL 的 hash 來模擬一個完整的 URL,於是當 URL 改變時,頁面不會重新加載。

類似於服務器路由,通過匹配不同的url路徑,進行解析,動態渲染出區域html,但是會出現一個問題,url每次發生變化都會導致頁面刷新。
解決思路也很簡單,在於改變url時頁面不刷新,同過加#,這樣後面的hash變化,不會使瀏覽器向服務器發生請求,而且在每次hash發生變化時,還會觸發hashChange方法,通過這個方法,監聽hashChange實現部分頁面的改變

function matchAndUpdate () {
   // todo 匹配 hash 做 dom 更新操作
}

window.addEventListener('hashchange', matchAndUpdate)
history模式

Html5在14年發佈之後,多了兩個API:pushState和replaceState,通過這兩個api改變url地址也不會發送請求,通過html5的api,url改變不用使用#,不過用戶刷新頁面的時候,需要服務器支持。把路由重定向到根頁面

vue-router使用

動態路由匹配

在vue項目中router.js中經常用到,把組件引入然後渲染。

const User = {
  template: '<div>User</div>'
}

const router = new VueRouter({
  routes: [
    // 動態路徑參數 以冒號開頭
    { path: '/user/:id', component: User }
  ]
})

其中參數路徑使用 :id,參數設置在 this.route.params使/user/foo/user/bar使調watchroute.params中。 當使用參數路由時,原來的組件實例會被複用,例如從/user/foo導航到/user/bar,**因爲使用同一組件,這也意味着生命週期的鉤子不會被調用**,複用組件時,想對參數發生變化,需要用到watch去監聽route

const User = {
  template: '...',
  watch: {
    '$route' (to, from) {
      // 對路由變化作出響應...
    }
  }
}
//或者使用2.2之後的beforeRouteUpdate
const User = {
  template: '...',
  beforeRouteUpdate (to, from, next) {
    // react to route changes...
    // don't forget to call next()
  }
}

嵌套路由

在vue的項目中,通常是多層路由嵌套

<div id="app">
  <router-view></router-view>
</div>

const User = {
  template: `
    <div class="user">
      <h2>User {{ $route.params.id }}</h2>
      <router-view></router-view>
    </div>
  `
}

const router = new VueRouter({
  routes: [
    { path: '/user/:id', component: User,
      children: [
        {
          // 當 /user/:id/profile 匹配成功,
          // UserProfile 會被渲染在 User 的 <router-view> 中
          path: 'profile',
          component: UserProfile
        },
        {
          // 當 /user/:id/posts 匹配成功
          // UserPosts 會被渲染在 User 的 <router-view> 中
          path: 'posts',
          component: UserPosts
        }
      ]
    }
  ]
})

先在app.js中第一曾router-view,然後在user中第二層,再使用children進行渲染組件

編程式導航

再vue項目內部,可以通過$router來進行路由訪問,例如

//html中
<router-link :to=''> 
//js中
this.$router.push

參數可以是一個字符串路徑,或者一個描述地址的對象:

// 字符串
router.push('home')

// 對象
router.push({ path: 'home' })

// 命名的路由
router.push({ name: 'user', params: { userId: 123 }})

// 帶查詢參數,變成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})

const userId = '123'
router.push({ name: 'user', params: { userId }}) // -> /user/123
router.push({ path: `/user/${userId}` }) // -> /user/123
// 這裏的 params 不生效
router.push({ path: '/user', params: { userId }}) // -> /user

//router.go(n)這個方法的參數是一個整數,意思是在 history 記錄中向前或者後退多少步,類似 window.history.go(n)
// 在瀏覽器記錄中前進一步,等同於 history.forward()
router.go(1)

// 後退一步記錄,等同於 history.back()
router.go(-1)

// 前進 3 步記錄
router.go(3)

// 如果 history 記錄不夠用,那就默默地失敗唄
router.go(-100)
router.go(100)

命名視圖

多個路由需要同級展示的時候,不如側邊欄和主內容,這時候需要設置name去識別

//name對應的是組件名字
<router-view class="view one"></router-view>
<router-view class="view two" name="a"></router-view>
<router-view class="view three" name="b"></router-view>

//在router.js裏面
const router = new VueRouter({
  routes: [
    {
      path: '/',
      components: {
        default: Foo,//Foo是組件名字
        a: Bar,//Bar是組件名字
        b: Baz//Baz是組件名字
      }
    }
  ]
})

重定向和別名

通過VueRouter也能進行路由的重定向

  1. 直接定向到url
const router = new VueRouter({
  routes: [
    { path: '/a', redirect: '/b' }
  ]
})
  1. 定向到name命名路由
const router = new VueRouter({
  routes: [
    { path: '/a', redirect: { name: 'foo' }}
  ]
})
  1. 重定向到方法
const router = new VueRouter({
  routes: [
    { path: '/a', redirect: to => {
      // 方法接收 目標路由 作爲參數
      // return 重定向的 字符串路徑/路徑對象
    }}
  ]
})

別名:

const router = new VueRouter({
  routes: [
    { path: '/a', component: A, alias: '/b' }
  ]
})

導航首位

再vue項目中,路由跳轉前要做一些驗證,比如在登陸,在權限中。

router.beforeEach

在router.js下面使用,可以放置一個全局的前置守衛

const router = new VueRouter({ ... })

router.beforeEach((to, from, next) => {
  // ...
})

可以看出有三個參數:

  • to:即將進入目標的路由對象
  • from:要離開的路由
  • next:調用該方法來 resolve 這個鉤子。執行效果依賴 next 方法的調用參數。
next(): 進行管道中的下一個鉤子。如果全部鉤子執行完了,則導航的狀態就是 confirmed (確認的)。

next(false): 中斷當前的導航。如果瀏覽器的 URL 改變了 (可能是用戶手動或者瀏覽器後退按鈕),那麼 URL 地址會重置到 from 路由對應的地址。

next('/') 或者 next({ path: '/' }): 跳轉到一個不同的地址。當前的導航被中斷,然後進行一個新的導航。你可以向 next 傳遞任意位置對象,且允許設置諸如 replace: true、name: 'home' 之類的選項以及任何用在 router-link 的 to prop 或 router.push 中的選項。

next(error): (2.4.0+) 如果傳入 next 的參數是一個 Error 實例,則導航會被終止且該錯誤會被傳遞給 router.onError() 註冊過的回調。
路由元信息(meta)

在配置路由的時候,每個路由可以添加一個自定義的meta,用來設置一些狀態

const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      children: [
        {
          path: 'bar',
          component: Bar,
          // a meta field
          meta: { requiresAuth: true }
        }
      ]
    }
  ]
})

如何使用meta呢,在to和from裏面可以調用,一個路由匹配到的所有路由記錄會暴露爲 $route 對象 (還有在導航守衛中的路由對象) 的 $route.matched 數組。因此,我們需要遍歷 $route.matched 來檢查路由記錄中的 meta 字段。

router.beforeEach((to, from, next) => {
  if (to.matched.some(record => record.meta.requiresAuth)) {
    // this route requires auth, check if logged in
    // if not, redirect to login page.
    if (!auth.loggedIn()) {
      next({
        path: '/login',
        query: { redirect: to.fullPath }
      })
    } else {
      next()
    }
  } else {
    next() // 確保一定要調用 next()
  }
})
全局解析守衛(router.beforeResolve) 2.5新增

這個方法與router.beforeEach類似,區別是在導航被確認之前,同時在所有組件內守衛和異步路由組件被解析之後,解析守衛就被調用。

全局後置鉤子(router.afterEach)
router.afterEach((to, from) => {
  // ...
})

註冊全局後置鉤子,然而和守衛不同的是,這些鉤子不會接受 next 函數也不會改變導航本身,只是一個抓取鉤子。

路由獨享守衛
const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        // ...
      }
    }
  ]
})
組件內的守衛

在vue組件中使用

  • beforeRouteEnter
  • beforeRouteUpdate (2.2 新增)
  • 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`
  }
}

beforeRouteEnter守衛不能訪問this,但是可以通過vm來訪問,而beforeRouteUpdate 和beforeRouteLeave來說,this已經可用了,所以不支持傳遞迴調

beforeRouteEnter (to, from, next) {
  next(vm => {
    // 通過 `vm` 訪問組件實例
  })
}
beforeRouteUpdate (to, from, next) {
  // just use `this`
  this.name = to.params.name
  next()
}
beforeRouteLeave (to, from , next) {
  const answer = window.confirm('Do you really want to leave? you have unsaved changes!')
  if (answer) {
    next()
  } else {
    next(false)
  }
}

完整的導航解析流程

1.導航被觸發。
2.在失活的組件裏調用離開守衛。
3.調用全局的 beforeEach 守衛。
4.在重用的組件裏調用 beforeRouteUpdate 守衛 (2.2+)。
5.在路由配置裏調用 beforeEnter。
6.解析異步路由組件。
7.在被激活的組件裏調用 beforeRouteEnter。
8.調用全局的 beforeResolve 守衛 (2.5+)。
9.導航被確認。
10.調用全局的 afterEach 鉤子。
11.觸發 DOM 更新。
12.用創建好的實例調用 beforeRouteEnter 守衛中傳給 next 的回調函數。

過度動效 (transition)

單個路由的過度動效

在transition中設置name

const Foo = {
  template: `
    <transition name="slide">
      <div class="foo">...</div>
    </transition>
  `
}
路由切換的過渡

具體可以看vue裏面的過渡效果

<!-- 使用動態的 transition name -->
<transition :name="transitionName">
  <router-view></router-view>
</transition>

watch: {
  '$route' (to, from) {
    const toDepth = to.path.split('/').length
    const fromDepth = from.path.split('/').length
    this.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left'
  }
}

數據獲取

數據獲取分兩種,導航前和導航後

//導航前
this.$route.params.id

//導航後
  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()
    })
  },

  1. params傳參,如果刷新頁面數據會被清空
  2. query傳參,放在url上,不會清空
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章