vue-router

vue-router

官網(wǎng)講解
簡述參考

安裝

  • npm install vue-router --save-dev 2.x
  • vue add vue-router 3.x

router 和route的區(qū)別

  1. router是VueRouter的一個對象,通過Vue.use(VueRouter)和VueRouter構(gòu)造函數(shù)得到一個router的實例對象,這個對象中是一個全局的對象。舉例:history對象。
  • $router.push({path:'home'});本質(zhì)是向history棧中添加一個路由
  • $router.replace({path:'home'});替換路由,沒有歷史記錄
  1. route是一個跳轉(zhuǎn)的路由對象,每一個路由都會有一個route對象,是一個局部的對象,可以獲取對應(yīng)的name,path,params,query等
  • $route.path
    字符串,等于當(dāng)前路由對象的路徑,會被解析為絕對路徑,如 "/home/news" 。
  • $route.params
    對象,包含路由中的動態(tài)片段和全匹配片段的鍵值對
  • route.query 對象,包含路由中查詢參數(shù)的鍵值對。例如,對于 /home/news/detail/01?favorite=yes ,會得到route.query.favorite == 'yes' 。
  • $route.router
    路由規(guī)則所屬的路由器(以及其所屬的組件)。
  • $route.matched
    數(shù)組,包含當(dāng)前匹配的路徑中所包含的所有片段所對應(yīng)的配置參數(shù)對象。
  • $route.name
    當(dāng)前路徑的名字,如果沒有使用具名路徑,則名字為空。

功能點

功能包括:

  • 嵌套路由/視圖映射
  • 模塊化,基于組件的路由器配置
  • 路線參數(shù),查詢,通配符
  • 查看由Vue.js過渡系統(tǒng)提供支持的過渡效果
  • 細(xì)粒度的導(dǎo)航控制
  • 與自動活動CSS類的鏈接
  • HTML5歷史模式或散列模式,在IE9中具有自動回退功能
  • 可自定義的滾動行為

要點

  1. 匹配任何東西,用'*'
{
  // will match everything
  //通常用于404客戶端
  path: '*'
}
{
  // will match anything starting with `/user-`
  path: '/user-*'
}
  1. 單擊<router-link :to="...">相當(dāng)于調(diào)用router.push(...)

  2. params和query

// literal string path
router.push('home')

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

// named route
router.push({ name: 'user', params: { userId: '123' } })

// with query, resulting in /register?plan=private
router.push({ path: 'register', query: { plan: 'private' } })
  1. name和path
const userId = '123'
router.push({ name: 'user', params: { userId } }) // -> /user/123
router.push({ path: `/user/${userId}` }) // -> /user/123
// This will NOT work
router.push({ path: '/user', params: { userId } }) // -> /user
  1. router.replace(location, onComplete?, onAbort?):作用就像router.push,唯一的區(qū)別是它導(dǎo)航時沒有按下新的歷史記錄條目,顧名思義 - 它取代了當(dāng)前的條目。

  2. router.go(n):指示在歷史堆棧中前進或后退的步數(shù),類似于window.history.go(n)

// go forward by one record, the same as history.forward()
router.go(1)

// go back by one record, the same as history.back()
router.go(-1)

// go forward by 3 records
router.go(3)

// fails silently if there aren't that many records.
router.go(-100)
router.go(100)
  1. 重定向和別名
//三種重定向的方式
const router = new VueRouter({
  routes: [
    { path: '/a', redirect: '/b' }
  ]
})

const router = new VueRouter({
  routes: [
    { path: '/a', redirect: { name: 'foo' }}
  ]
})

const router = new VueRouter({
  routes: [
    { path: '/a', redirect: to => {
      // the function receives the target route as the argument
      // return redirect path/location here.
      return '/b'
    }}
  ]
})
//別名
const router = new VueRouter({
  routes: [
    { path: '/a', component: A, alias: '/b' }
  ]
})
  1. props ???
routes:[
  path:'/home/:id',
  props:true,
]

export default{
  props:['id'],
  mounted(){
    console.log(this.id)
  }
}
  1. mode: 'history', 路由中去掉#號,利用history.pushStateAPI實現(xiàn)URL導(dǎo)航而無需重新加載頁面。mode: 'hash',

響應(yīng)路由參數(shù)的變化

當(dāng)路由參數(shù)發(fā)生變化時,復(fù)用組件實例。兩種方式:

const User = {
  template: '...',
  watch: {
    '$route' (to, from) {
      // react to route changes...
    }
  }
}

const User = {
  template: '...',
  beforeRouteUpdate (to, from, next) {
    // react to route changes...
    // don't forget to call next()
  }
}
  1. 路由樣式
    exact 精確匹配
linkExactActiveClass: 'active-exact',
linkActiveClass: 'active',

歷史操縱

You may have noticed that router.push, router.replace and router.go are counterparts of window.history.pushState, window.history.replaceState and window.history.go, and they do imitate the window.history APIs.

命名視圖(插座)

<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>

const router = new VueRouter({
  routes: [
    {
      path: '/',
      components: {
        default: Foo,
        a: Bar,
        b: Baz
      }
    }
  ]
})

導(dǎo)航守衛(wèi) Navigation Guards

導(dǎo)航守衛(wèi)有點類似 中間件,進入 路由 前 先通過守衛(wèi),來判斷是否可以通過,進而到達(dá)頁面。

每個守衛(wèi)功能都有三個參數(shù):

  • to: Route:導(dǎo)航到的目標(biāo)Route對象。

  • from: Route:當(dāng)前路線被導(dǎo)航離開。

  • next: Function:必須調(diào)用此函數(shù)來解析鉤子。該操作取決于提供給的參數(shù)next:

    • next():繼續(xù)前進到管道中的下一個鉤子。如果沒有留下掛鉤,則確認(rèn)導(dǎo)航。

    • next(false):中止當(dāng)前導(dǎo)航。如果瀏覽器URL已更改(由用戶手動或通過后退按鈕),則會將其重置為from路徑的URL 。

    • next('/')或next({ path: '/' }):重定向到其他位置。當(dāng)前導(dǎo)航將中止,并將啟動一個新導(dǎo)航。你可以通過任何位置對象next,它允許您指定類似的選項replace: true,name: 'home'在使用任何選項router-link的to道具或router.push

    • next(error):(2.4.0+)如果傳遞給的參數(shù)next是一個實例Error,導(dǎo)航將被中止,錯誤將傳遞給通過注冊的回調(diào)router.onError()。

確保始終調(diào)用該next函數(shù),否則永遠(yuǎn)不會解析掛鉤。

全局守衛(wèi)(在定義router的地方定義)


//全局鉤子
//使用router.beforeEach注冊一個全局 前置守衛(wèi)
router.beforeEach((to, from, next) => {
  // some every  路由元信息
  const needLogin = to.matched.some(route => route.meta && route.meta.login);
  if (needLogin) {
    // 檢驗
    const isLogin = document.cookie.includes('login=true');
    if (isLogin) {
      next();
      return;
    }
    const toLoginFlag = window.confirm('該頁面需要登錄后訪問,要去登陸嗎?');

    if (toLoginFlag) {
      next('/login');
    }

    return;
  }
  next();
})

//使用router.beforeResolve注冊一個全局解析守衛(wèi)
//在導(dǎo)航被確認(rèn)之前,同時在所有組件內(nèi)守衛(wèi)和異步路由組件被解析之后,解析守衛(wèi)就被調(diào)用
router.beforeResolve((to, from, next) => {
  console.log('beforeResolve');
  next();
})

//router.beforeResolv注冊全局后置鉤子
//不會接受 next 函數(shù)也不會改變導(dǎo)航本身
router.afterEach(() => {
  console.log('afterEach');
})

路由獨享的守衛(wèi)(在路由內(nèi)定義)

routes:[
  {
    path:
    name:
    component:
    beforeEnter:(to,from,next)=>{
      console.log('路由內(nèi)的守衛(wèi)導(dǎo)航')
    }
  }
]

組件內(nèi)的守衛(wèi)(在組件內(nèi)定義)

注意 beforeRouteEnter 是支持給 next傳遞回調(diào)的唯一守衛(wèi)。對于 beforeRouteUpdatebeforeRouteLeave 來說,this 已經(jīng)可用了,所以不支持傳遞回調(diào),因為沒有必要了。

beforeRouteEnter(to,from,next){
  next(vm=>{
    //通過'vm'訪問組件實例
  })
}

beforeRouteUpdate(to,from,next){
  //使用this
  this.name = to.params.name
  next()
}

// 這個離開守衛(wèi)通常用來  禁止用戶在還未保存修改前突然離開  。該導(dǎo)航可以通過 next(false) 來取消。
 beforeRouteLeave(to,from,next){
   const answer = window.confirm('leave?save?')
   answer?next():next(false) 
 }

進入某一個路徑時,執(zhí)行順序

  • beforeEach -> beforeEnter -> beforeRouteEnter -> beforeResolve -> afterEach

完整的導(dǎo)航解析流程

  • 導(dǎo)航被觸發(fā)。
  • 在失活的組件里調(diào)用離開守衛(wèi)。
  • 調(diào)用全局的 beforeEach 守衛(wèi)。
  • 在重用的組件里調(diào)用 beforeRouteUpdate 守衛(wèi) (2.2+)。
  • 在路由配置里調(diào)用 beforeEnter。
  • 解析異步路由組件。
  • 在被激活的組件里調(diào)用 beforeRouteEnter。
  • 調(diào)用全局的 beforeResolve 守衛(wèi) (2.5+)。
  • 導(dǎo)航被確認(rèn)。
  • 調(diào)用全局的 afterEach 鉤子。
  • 觸發(fā) DOM 更新。
  • 用創(chuàng)建好的實例調(diào)用 beforeRouteEnter 守衛(wèi)中傳給 next 的回調(diào)函數(shù)。

路由元信息 Route Meta Fields

  • 存儲路由信息 meta = {}

過渡動效 Transitions

<!-- use a dynamic transition name -->
<transition :name="transitionName">
  <router-view></router-view>
</transition>
// then, in the parent component,
// watch the `$route` to determine the transition to use
watch: {
  '$route' (to, from) {
    const toDepth = to.path.split('/').length
    const fromDepth = from.path.split('/').length
    this.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left'
  }
}

數(shù)據(jù)提取

  • 導(dǎo)航完成之后獲取:先完成導(dǎo)航,然后在接下來的組件生命周期鉤子中獲取數(shù)據(jù)。在數(shù)據(jù)獲取期間顯示“加載中”之類的指示。
<template>
  <div class="post">
    <div v-if="loading" class="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 () {
    //組件創(chuàng)建后完成獲取數(shù)據(jù)
    //此時的data已經(jīng)被observed
    this.fetchData()
  },
  watch: {
    //如果路由有變化,會再次執(zhí)行該方法
    '$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
        }
      })
    }
  }
}
  • 在導(dǎo)航之前獲取:導(dǎo)航完成前,在路由進入的守衛(wèi)中獲取數(shù)據(jù),在數(shù)據(jù)獲取成功后執(zhí)行導(dǎo)航。
//過這種方式,我們在導(dǎo)航轉(zhuǎn)入新的路由前獲取數(shù)據(jù)。我們可以在接下來的組件的 beforeRouteEnter守衛(wèi)中獲取數(shù)據(jù),當(dāng)數(shù)據(jù)獲取成功后只調(diào)用 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))
    })
  },
  // when route changes and this component is already rendered,
  // the logic will be slightly different.
  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 desired position
  }

  scrollBehavior (to, from, savedPosition) {
    if (savedPosition) {
      return savedPosition
    } else {
      return { x: 0, y: 0 }
    }
  }

  scrollBehavior (to, from, savedPosition) {
    if (to.hash) {
      return {
        selector: to.hash
        // , offset: { x: 0, y: 10 }
      }
    }
  }
})

懶加載路由

//webpack會將具有相同塊名稱的任何異步模塊分組到同一個異步塊中。
const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')
const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue')
const Baz = () => import(/* webpackChunkName: "group-foo" */ './Baz.vue')
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容