vue-route

程式設計師的貓發表於2019-10-25
    由於Vue在開發時對路由支援的不足,於是官方補充了vue-router外掛。vue的單頁面應用是基於路由和元件的,路由用於設定訪問路徑,並將路徑和元件對映起來。傳統的頁面應用,是用一些超連結來實現頁面切換和跳轉的。在vue-router單頁面應用中,則是路徑之間的切換,實際上就是元件的切換。路由就是SPA(單頁應用)的路徑管理器。再通俗的說,vue-router就是我們WebApp的連結路徑管理系統。

  有的小夥伴會有疑慮,為什麼我們不能像原來一樣直接用a標籤編寫連結呢?因為我們一般用Vue做的都是單頁應用,只有一個主頁面index.html,所以你寫的標籤是不起作用的,要使用vue-router來進行管理。

一、安裝

如果你用vue-cli腳手架來搭建專案,配置過程會選擇是否用到路由(詳細見我上一篇簡書),如果選擇y,後面下載依賴會自動下載vue-router。
這裡還是說一下安裝:npm install vue-router

二、建立元件

如果在一個模組化工程中使用它,必須要透過 Vue.use() 明確地安裝路由功能,用vue-cli生產了我們的專案結構,src檔案目錄下會有一個router資料夾,此處就是編寫路由元件的地方。在src/router/index.js,這個檔案就是路由的核心檔案:

import Vue from 'vue'   //引入Vueimport Router from 'vue-router'  //引入vue-routerimport Hello from '@/components/Hello'  //引入根目錄下的Hello.vue元件
 Vue.use(Router)  //Vue全域性使用Router
 export default new Router({  routes: [              //配置路由,這裡是個陣列
    {                    //每一個連結都是一個物件
      path: '/',         //連結路徑
      name: 'Hello',     //路由名稱,
      component: Hello   //對應的元件模板
    },{      path:'/hi',      component:Hi,      children:[        //子路由,巢狀路由 (此處偷個懶,免得單獨再列一點)
        {path:'/',component:Hi},
        {path:'hi1',component:Hi1},
        {path:'hi2',component:Hi2},
      ]
    }
  ]
})

三、router-link製作導航

1.router-link 是一個元件,它預設會被渲染成一個帶有連結的a標籤,透過to屬性指定連結地址。
注意:被選中的router-link將自動新增一個class屬性值.router-link-active。

<router-link to="/">[text]</router-link>
  • to:導航路徑,要填寫的是你在router/index.js檔案裡配置的path值,如果要導航到預設首頁,只需要寫成  to="/"  ,

  • [text] :就是我們要顯示給使用者的導航名稱。

2.router-view 用於渲染匹配到的元件。
①.可以給router-view元件設定transition過渡Vue2.0 Transition常見用法全解惑)。

<transition name="fade">  <router-view ></router-view></transition>

css過渡類名:
元件過渡過程中,會有四個CSS類名進行切換,這四個類名與transition的name屬性有關,比如name="fade",會有如下四個CSS類名:

  • fade-enter:進入過渡的開始狀態,元素被插入時生效,只應用一幀後立刻刪除。

  • fade-enter-active:進入過渡的結束狀態,元素被插入時就生效,在過渡過程完成後移除。

  • fade-leave:離開過渡的開始狀態,元素被刪除時觸發,只應用一幀後立刻刪除。

  • fade-leave-active:離開過渡的結束狀態,元素被刪除時生效,離開過渡完成後被刪除。

從上面四個類名可以看出,fade-enter-activefade-leave-active在整個進入或離開過程中都有效,所以CSS的transition屬性在這兩個類下進行設定。

過渡模式mode:

  • in-out(mode預設in-out模式):新元素先進入過渡,完成之後當前元素過渡離開。

  • out-in:當前元素先進行過渡離開,離開完成後新元素過渡進入。

②.還可以配合<keep-alive>使用,keep-alive可以快取資料,這樣不至於重新渲染路由元件的時候,之前那個路由元件的資料被清除了。比如對當前的路由元件a進行了一些DOM操作之後,點選進入另一個路由元件b,再回到路由元件a的時候之前的DOM操作還儲存在,如果不加keep-alive再回到路由元件a時,之前的DOM操作就沒有了,得重新進行。如果你的應用裡有一個購物車元件,就需要用到keep-alive。

<transition>
  <keep-alive>
    <router-view></router-view>
  </keep-alive></transition>

四、動態路由匹配

我們經常需要把某種模式匹配到的所有路由,全都對映到同個元件。
呼叫router的map方法對映路由,每條路由以key-value的形式存在,key是路徑,value是元件。例如:'/home'是一條路由的key,它表示路徑;{component: Home}則表示該條路由對映的元件:

router.map({    '/home': { component: Home },    '/about': { component: About }
})

例如,我們有一個 User 元件,對於所有 ID 各不相同的使用者,都要使用這個元件來渲染。那麼,我們可以在 vue-router 的路由路徑中使用『動態路徑引數』來達到這個效果。

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

例如: /user/foo 和 /user/bar 都將對映到相同的路由。
一個『路徑引數』使用冒號 : 標記。當匹配到一個路由時,引數值會被設定到this.$route.params,可以在每個元件內使用。
你可以在一個路由中設定多段『路徑引數』,對應的值都會設定到 $route.params 中。例如:

vue-route

五、vue-router引數傳遞

1.用name傳值(不推薦)

vue-route

2.透過 標籤中的to傳參
<router-link :to="{name:‘dxl’,params:{key:value}}">東西里</router-link>
  • name:就是我們在路由配置檔案中起的name值。
    另:命名路由就是用一個名稱來標識一個路由,在定義路由的時候設定一個name屬性即可。在router-link中也可以用路由的名字來連結到一個路由。

  • params:就是我們要傳的引數,它也是物件形勢,在物件裡可以傳遞多個值。\
    最後用$route.params.username進行接收.

3.用url傳參

上面第五點也有提到。   :冒號的形式傳遞引數\
(1).在router路由配置檔案裡以冒號的形式設定引數

{
    path:'/params/:newsId/:userName,
    component:Params
}

(2).元件形式,在src/components目錄下建立我們params.vue元件。
我們在頁面裡輸出了url傳遞的引數。

<template>
    <div>
        <h2>{{ msg }}</h2>
        <p>新聞ID:{{ $route.params.newsId}}</p>
        <p>使用者名稱:{{ $route.params.userName}}</p>
    </div></template><script>export default {  name: 'params',
  data () {    return {      msg: 'params page'
    }
  }
}</script>

(3).標籤path路徑中傳值

<router-link to="/params/888/dxl shuai>params</router-link> 

(4).正規表示式在URL傳值中的應用
希望我們傳遞的新聞ID只能是數字的形式,這時候我們就需要在傳遞時有個基本的型別判斷,path:'/params/:newsId(\\d+)/:userName'

六.響應路由引數的變化

當使用路由引數時,例如從 /user/foo 導航到 /user/bar,原來的元件例項會被複用。因為兩個路由都渲染同個元件,比起銷燬再建立,複用則顯得更加高效。不過,這也意味著元件的生命週期鉤子不會再被呼叫。
複用元件時,想對路由引數的變化作出響應的話:
(1). watch(監測變化) $route 物件:

const User = {  template: '...',  watch: {    '$route' (to, from) {      // 對路由變化作出響應...
    }
  }
}

(2).beforeRouteUpdate 導航守衛\
如果目的地和當前路由相同,只有引數發生了改變 (比如從一個使用者資料到另一個 /users/1 -> /users/2),你需要使用 beforeRouteUpdate來響應這個變化 (比如抓取使用者資訊)。

const User = {  template: '...',
  beforeRouteUpdate (to, from, next) {    // react to route changes...
    // don't forget to call next()
  }
}

七、實現不同路由不同頁面標題

// 定義路由的時候如下定義,name也可為中文const routes = [
  { path: '/goods', component: goods, name: 'goods' },
  { path: '/orders', component: orders, name: 'orders' },
  { path: '/seller', component: seller, name: 'seller' }
];// 建立路由例項const router = new VueRouter({  routes: routes
})// 關鍵在這裡,設定afterEach鉤子函式router.afterEach((to, from, next) => {  document.title = to.name;
})

八、重定向

剛進入應用都是進入到“/”這個路由的,如果想直接進入到“/goods”怎麼辦,有兩種方法。一種是利用重定向,另一種是利用vue-router的導航式程式設計。
redirect基本重定向:

const routes = [
  { path: '/', redirect: '/goods'}
]
重定向的目標也可以是一個命名的路由。const routes = [
  { path: '/', redirect: { name: 'goods' }}
]
重定向時也可以傳遞引數
{
  path:'/',
  redirect:'/goods/:newsId(\\d+)/:userName'}

.這裡不得不提到alias別名的使用。

1.首先我們在路由配置檔案裡給路徑起一個別名,dxl。

{    path: '/hi',
    component: Hi,
    alias:'/dxl'
 }

2.配置我們的<router-link>,起過別名之後,可以直接使用<router-link>標籤裡的to屬性,進行重新定向。

<router-link to="/dxl">jspang</router-link>

區別:

  • redirect:仔細觀察URL,redirect是直接改變了url的值,把url變成了真實的path路徑。

  • alias:URL路徑沒有別改變,這種情況更友好,讓使用者知道自己訪問的路徑,只是改變了中的內容。

.注意一個大坑:
別名alias在path為'/'中,是不起作用的。

{  path: '/',
  component: Hello,
  alias:'/home'}

九、程式設計式導航

1.router.push( )
想要導航到不同的 URL,則使用 router.push (在建立vue例項並掛載後呼叫)。router.push方法就是用來動態導航到不同的連結的,這個方法會向 history 棧新增一個新的記錄,所以,當使用者點選瀏覽器後退按鈕時,則回到之前的 URL。
當你點選 時,這個方法會在內部呼叫,所以說,點選 等同於呼叫 router.push(...)。

vue-route

注意:
如果提供了 path,params 會被忽略,而 query 並不屬於這種情況。取而代之的是下面例子的做法,你需要提供路由的 name 或手寫完整的帶有引數的 path:

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

2.router.replace( )
router.replace跟 router.push 很像,唯一的不同就是,它不會向 history 新增新記錄,而是跟它的方法名一樣 —— 替換掉當前的 history 記錄。

vue-route

3.router.go(n)
這個方法的引數是一個整數,意思是在 history 記錄中向前或者後退多少步,類似 window.history.go(n)。

// 在瀏覽器記錄中前進一步,等同於 history.forward()router.go(1)// 後退一步記錄,等同於 history.back()router.go(-1)

自定義一個goback()方法,並使用this.$router.go(-1),進行後退操作

<script>export default {  name: 'app',  methods:{
    goback(){      this.$router.go(-1);
    },
    goHome(){      this.$router.push('/');
    }
  }
}</script>

十、路由中的鉤子

1.路由配置檔案中的鉤子函式:
在路由檔案中我們只能寫一個beforeEnter,就是在進入此路由配置時:

{      path:'/params/:newsId(\\d+)/:userName',      component:Params,      beforeEnter:(to,from,next)=>{        console.log('我進入了params模板');        console.log(to);        console.log(from);
        next();
},

三個引數:

  • to:路由將要跳轉的路徑資訊,資訊是包含在對像裡邊的。

  • from:路徑跳轉前的路徑資訊,也是一個物件的形式。

  • next:路由的控制引數,常用的有next(true)和next(false)。

2.寫在模板中的鉤子函式:\
寫在模板中就可以有兩個鉤子函式可以使用。
beforeRouteEnter:在路由進入前的鉤子函式。
beforeRouteLeave:在路由離開前的鉤子函式。

export default {  name: 'params',
  data () {    return {      msg: 'params page'
    }
  },  beforeRouteEnter:(to,from,next)=>{    console.log("準備進入路由模板");
    next();
  },  beforeRouteLeave: (to, from, next) => {    console.log("準備離開路由模板");
    next();
  }
}

此處常用於資料獲取

  • 導航完成之後獲取:先完成導航,然後在接下來的元件生命週期鉤子中獲取資料。在資料獲取期間顯示『載入中』之類的指示。
    當你使用這種方式時,我們會馬上導航和渲染元件,然後在元件的 created 鉤子中獲取資料。這讓我們有機會在資料獲取期間展示一個 loading 狀態,還可以在不同檢視間展示不同的 loading 狀態。
    假設我們有一個 Post 元件,需要基於 $route.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
            }
          })
        }
      }
    }
  • 導航完成之前獲取:導航完成前,在路由進入的守衛中獲取資料,在資料獲取成功後再執行導航。
    透過這種方式,我們在導航轉入新的路由前獲取資料。我們可以在接下來的元件的 beforeRouteEnter 守衛中獲取資料,當資料獲取成功後只呼叫 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))
        })
      },  // 路由改變前,元件就已經渲染完了
      // 邏輯稍稍不同
      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
          }
        }
      }
    }

    十一、History 模式

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

如果不想要很醜的 hash,我們可以用路由的 history 模式,這種模式充分利用 history.pushState API 來完成 URL 跳轉而無須重新載入頁面。

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

在學習過渡效果的時候,我們學了mode的設定,但是在路由的屬性中還有一個mode。
mode的兩個值:

  • histroy:當你使用 history 模式時,URL 就像正常的 url,http://www.dxl.com/user/id\
    不過這種模式要玩好,還需要後臺配置支援。因為我們的應用是個單頁客戶端應用,如果後臺沒有正確的配置,當使用者在瀏覽器直接訪問 http://www.dxl.com/user/id就會返回 404,。所以要在服務端增加一個覆蓋所有情況的候選資源:如果 URL 匹配不到任何靜態資源,則應該返回同一個 index.html 頁面,這個頁面就是你 app 依賴的頁面。

vue-route

這麼做以後,你的伺服器就不再返回 404 錯誤頁面,因為對於所有路徑都會返回 index.html 檔案。**為了避免這種情況,你應該在 Vue 應用裡面覆蓋所有的路由情況,然後在給出一個 404 頁面。**
const router = new VueRouter({  mode: 'history',  routes: [
    { path: '*', component: Error}
  ]
})

這裡的path:'*'就是找不到頁面時的配置,component是我們新建的一個Error.vue的檔案

  • hash:預設’hash’值,但是hash看起來就像無意義的字元排列,不太好看也不符合我們一般的網址瀏覽習慣。不配置時是這樣的:http://localhost:8080/#/users,多個#號。

十二、路由元件傳參

(這點是直接貼上的vue官網上的教程,此處是重點要多看多體會!)\
在元件中使用 $route 會使之與其對應路由形成高度耦合,從而使元件只能在某些特定的 URL 上使用,限制了其靈活性。\
解耦前:\
id不能直接拿出來使用

const User = {
  template: '<div>User {{ $route.params.id }}</div>'}const router = new VueRouter({
  routes: [
    { path: '/user/:id', component: User }
  ]
})

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

這樣你便可以在任何地方使用該元件,使得該元件更易於重用和測試。

1.布林模式\
如果 props 被設定為 true,route.params 將會被設定為元件屬性。

2.物件模式\
如果 props 是一個物件,它會被按原樣設定為元件屬性。當 props 是靜態的時候有用。

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

3.函式模式
你可以建立一個函式返回 props。這樣你便可以將引數轉換成另一種型別,將靜態值與基於路由的值結合等等。

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

/search?q=vue會將{query: 'vue'}作為屬性傳遞給 SearchUser 元件。
請儘可能保持 props 函式為無狀態的,因為它只會在路由發生變化時起作用。如果你需要狀態來定義 props,請使用包裝元件,這樣 Vue 才可以對狀態變化做出反應。

function dynamicPropsFn (route) {  const now = new Date()  return {    name: (now.getFullYear() + parseInt(route.params.years)) + '!'
  }
}const router = new VueRouter({  mode: 'history',  base: __dirname,  routes: [
    { path: '/', component: Hello }, // No props, no nothing
    { path: '/hello/:name', component: Hello, props: true }, // Pass route.params to props
    { path: '/static', component: Hello, props: { name: 'world' }}, // static values
    { path: '/dynamic/:years', component: Hello, props: dynamicPropsFn }, // custom logic for mapping between route and props
    { path: '/attrs', component: Hello, props: { name: 'attrs' }}
  ]
})
本作品採用《CC 協議》,轉載必須註明作者和本文連結
你還差得遠吶!