Vue 路由詳解

Vue 路由詳解

對於前端來講,其實瀏覽器配合超級鏈接就很好的實現了路由功能。可是對於單頁面應用來講,瀏覽器和超級鏈接的跳轉方式已經不能適用,因此各大框架紛紛給出了單頁面應用的解決路由跳轉的方案。html

Vue 框架的兼容性很是好,能夠很好的跟其餘第三方的路由框架進行結合。固然官方也給出了路由的方案: vue-router;前端

建議仍是用官方的最好,使用量也是最大,相對來講 Vue 框架的升級路由組件升級也會及時跟上,因此爲了之後的維護和升級方便仍是使用 Vue 自家的東西最好。vue

Vue-router 的版本對應

注意: vue-router@3.0+ 依賴 vue@2.5+
vue-router@2.x 只適用於 Vue 2.x 版本。
vue-router@1.x 對應於 Vue1.x 版本。react

vue-router 的安裝使用

  • CDN 鏈接方式

https://unpkg.com/vue-router/dist/vue-router.jswebpack

  • npm 安裝
npm install vue-router

 

相關的概念

路由相關的對象和組件:git

  • Router實例:配置路由規則和控制路由跳轉及配置路由鉤子的實例,由VueRouter構造函數構建,並由根vue實例注入到全部的子組件。
  • Route對象:一個路由對象 (route object) 表示當前激活的路由的狀態信息,包含了當前 URL 解析獲得的信息,還有 URL 匹配到的路由記錄 (route records)。
  • router-link組件<router-link> 組件支持用戶在具備路由功能的應用中(點擊)導航。經過 to 屬性指定目標地址,默認渲染成帶有正確連接的 <a> 標籤,能夠經過配置 tag 屬性生成別的標籤.。另外,當目標路由成功激活時,連接元素自動設置一個表示激活的 CSS 類名。
  • router-view組件<router-view> 組件是一個 functional 組件,渲染路徑匹配到的視圖組件。<router-view>渲染的組件還能夠內嵌本身的 <router-view>,根據嵌套路徑,渲染嵌套組件。

vue-router 入門 demo

vue-router 開發的步驟es6

  • 第一步: 引入 vue 和 vue-router 包。

    可使用 cdn 的方式或者 npm 的方式。若是配合 npm 和 webpack 的話能夠直接做爲一個模塊導入便可。可是做爲初學入門的話建議仍是 直接使用 cdn 包的形式,先學會怎麼用路由。github

<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>

 

  • 第二步: 定義路由跳轉的組件
// 1. 定義(路由)組件。
const Foo = { template: '<div>foo</div>' };
const Bar = { template: '<div>bar</div>' };

 

 
  • 第三步: 定義路由規則對象
// 每一個路由path應該映射一個組件。 其中"component" 能夠是 // 經過 Vue.extend() 建立的組件構造器, // 或者,只是一個組件配置對象。
const routes = [
  { path: '/foo', component: Foo },
  { path: '/bar', component: Bar }
];

 

// 建立路由對象
const router = new VueRouter({
  routes // (縮寫)至關於 routes: routes,es6的新語法
});

 

 
  • 第四步: 建立 Vue 對象,並加劇上面建立的路由對象
// 記得要經過 router 配置參數注入路由,
// 從而讓整個應用都有路由功能
const app = new Vue({
  router
}).$mount('#app');

 

  • 第五步: 在模板中編寫路由跳轉連接
<div id="app">
  <h1>Hello App!</h1>
  <p>
    <!-- 使用 router-link 組件來導航. -->
    <!-- 經過傳入 `to` 屬性指定連接. -->
    <!-- <router-link> 默認會被渲染成一個 `<a>` 標籤 -->
    <router-link to="/foo">Go to Foo</router-link>
    <router-link to="/bar">Go to Bar</router-link>
  </p>
  <!-- 路由出口 -->
  <!-- 路由匹配到的組件將渲染在這裏 -->
  <router-view></router-view>
</div>

 

最終的代碼web

<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>

<div id="app">
  <h1>Hello App!</h1>
  <p>
    <!-- 使用 router-link 組件來導航. -->
    <!-- 經過傳入 `to` 屬性指定連接. -->
    <!-- <router-link> 默認會被渲染成一個 `<a>` 標籤 -->
    <router-link to="/foo">Go to Foo</router-link>
    <router-link to="/bar">Go to Bar</router-link>
  </p>
  <!-- 路由出口 -->
  <!-- 路由匹配到的組件將渲染在這裏 -->
  <router-view></router-view>
</div>
<script>
// 1. 定義(路由)組件。
// 能夠從其餘文件 import 進來
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }

// 2. 定義路由
const routes = [
  { path: '/foo', component: Foo },
  { path: '/bar', component: Bar }
]

// 3. 建立 router 實例,而後傳 `routes` 配置
// 你還能夠傳別的配置參數, 不過先這麼簡單着吧。
const router = new VueRouter({
  routes // (縮寫)至關於 routes: routes
})

// 4. 建立和掛載根實例。
// 記得要經過 router 配置參數注入路由,
// 從而讓整個應用都有路由功能
const app = new Vue({
  router
}).$mount('#app')
</script>

 

使用 vue-router 的綜合實例

下面是一個綜合的例子, 頁面上有幾個導航的按鈕,而後經過點擊不一樣的按鈕,能夠在當前頁面切換不一樣的組件。vue-router

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Vue入門之extend全局方法</title>
  <script src="https://unpkg.com/vue/dist/vue.js"></script>
  <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
  <style>
  ul, li { list-style: none; }
  ul { overflow: hidden; }
  li { float: left; width: 100px; }
  h2 { background-color: #903;}
  </style>
</head>
<body>
  <div id="app">
    <top-bar> </top-bar>
    <hr>
      <p>email to: {{ email }}</p>
    <hr>
    <router-view class="view one"></router-view>
    <footer-bar></footer-bar>
  </div>
  <script>
    var topbarTemp = `
      <nav>
        <ul>
          <li v-for="item in NavList">
            <router-link :to="item.url">{{ item.name }}</router-link>
          </li>
        </ul>
      </nav>
    `;
    // 定義組件:topbar
    Vue.component('top-bar', {
      template: topbarTemp,
      data: function () {
        return {
          NavList: [
            { name: '首頁', url: '/home'},
            { name: '產品', url: '/product'},
            { name: '服務', url: '/service'},
            { name: '關於', url: '/about'}
          ]
        }
      }
    });

    Vue.component('footer-bar', {  // 定義組件 footerbar
      template: `
        <footer>
          <hr/>
          <p>版權全部@flydragon<p>
        </footer>
      `
    });

    // 建立home模塊
    var home = {
      template: `<div> <h2>{{ msg }}<h2></div>`,
      data: function () {
        return { msg: 'this is home view' }
      }
    };

    // 建立product 模塊
    var product = {
      template: `<div> {{ msg }}</div>`,
      data: function () {
        return { msg: 'this is product view' }
      }
    }

    // 定義路由對象
    var router = new VueRouter({
      routes: [
        { path: '/home', component: home },
        { path: '/product', component: product }
      ]
    });

    // 初始化一個Vue實例
    var app = new Vue({
      el: '#app',
      data: {
       email: 'flydragon@gmail.com'
      },
      router: router
    });
  </script>
</body>
</html>

 

動態路由匹配

咱們常常須要把某種模式匹配到的全部路由,全都映射到同個組件。例如,咱們有一個 User 組件,對於全部 ID 各不相同的用戶,都要使用這個組件來渲染。那麼,咱們能夠在 vue-router 的路由路徑中使用『動態路徑參數』(dynamic segment)來達到這個效果:

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

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

 

如今呢,像 /user/foo 和 /user/bar 都將映射到相同的路由。

一個『路徑參數』使用冒號 : 標記。當匹配到一個路由時,參數值會被設置到 this.$route.params,能夠在每一個組件內使用。因而,咱們能夠更新 User 的模板,輸出當前用戶的 ID:

const User = {
  template: '<div>User {{ $route.params.id }}</div>'
}

 

你能夠看看這個在線例子

你能夠在一個路由中設置多段『路徑參數』,對應的值都會設置到 $route.params 中。例如:

模式 匹配路徑 $route.params
/user/:username /user/evan { username: 'evan' }
/user/:username/post/:post_id /user/evan/post/123 { username: 'evan', post_id: 123 }

除了 $route.params 外,$route 對象還提供了其它有用的信息,例如,$route.query(若是 URL 中有查詢參數)、$route.hash 等等。你能夠查看 API 文檔 的詳細說明。

響應路由參數的變化

提醒一下,當使用路由參數時,例如從 /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-router 使用 path-to-regexp 做爲路徑匹配引擎,因此支持不少高級的匹配模式,例如:可選的動態路徑參數、匹配零個或多個、一個或多個,甚至是自定義正則匹配。查看它的 文檔 學習高階的路徑匹配,還有 這個例子 展現 vue-router 怎麼使用這類匹配。

匹配優先級

有時候,同一個路徑能夠匹配多個路由,此時,匹配的優先級就按照路由的定義順序:誰先定義的,誰的優先級就最高。

路由參數獲取

定義路由路徑的時候,能夠指定參數。參數須要經過路徑進行標識:/user/:id就是定義了一個規則,/user 開頭,而後後面的就是 id 參數的值。 好比:

路由規則:  /user/:id
/user/9   =>  id = 9
/user/8   =>  id = 8
/user/1   =>  id = 1

 

而後在跳轉後的 vue 中能夠經過this.$route.params.參數名獲取對應的參數。 好比代碼:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Vue入門之extend全局方法</title>
  <script src="https://unpkg.com/vue/dist/vue.js"></script>
  <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
</head>

<body>
  <div id="app">
    <nav>
      <router-link to="/user/9">用戶</router-link>
      <router-link to="/stu/malun">學生</router-link>
      <hr>
    </nav>
    <router-view></router-view>
  </div>
  <script>
    var user = {
      template: `
        <div>user id is : {{ $route.params.id }}</div>
      `
    };

    var stu = {
      template: `
        <div>
          <h2>{{ getName }}</h2>
        </div>
      `,
      computed: {
        getName: function () {
          return this.$route.params.name;
        }
      }
    };
    var router = new VueRouter({
      routes: [
        { path: '/user/:id', component: user },
        { path: '/stu/:name', component: stu }
      ]
    });
    var app = new Vue({
      el: '#app',
      router: router
    });
  </script>
</body>
</html>

 

js 控制路由跳轉

上面咱們演示的都是經過 router-link 進行跳轉。 其實咱們還能夠經過 js 編程的方式進行路由的跳轉。

咱們能夠在任何組件內經過 this.$router 訪問路由器,也能夠經過 this.$route 訪問當前路由.

當你點擊 <router-link> 時,這個方法會在內部調用,因此說,點擊 <router-link :to="..."> 等同於調用 router.push(...)

聲明式 編程式
<router-link :to="..."> router.push(...)
// 當前路由的view跳轉到 /home
this.$router.push('home');

// 對象,  跳轉到/home
this.$router.push({ path: 'home' });

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

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

 

注意:若是提供了 pathparams 會被忽略,上述例子中的 query 並不屬於這種狀況。取而代之的是下面例子的作法,你須要提供路由的 name 或手寫完整的帶有參數的 path

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-link 組件的 to 屬性。

router.replace(location, onComplete?, onAbort?)

跟 router.push 很像,惟一的不一樣就是,它不會向 history 添加新記錄,而是跟它的方法名同樣 —— 替換掉當前的 history 記錄。

聲明式 編程式
<router-link :to="..." replace> router.replace(...)

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)

 

操做 History

你也許注意到 router.push、 router.replace 和 router.go 跟 window.history.pushState、 window.history.replaceState 和 window.history.go好像, 實際上它們確實是效仿 window.history API 的。

所以,若是你已經熟悉 Browser History APIs,那麼在 vue-router 中操做 history 就是超級簡單的。

還有值得說起的,vue-router 的導航方法 (push、 replace、 go) 在各種路由模式(history、 hash 和 abstract)下表現一致。

命名路由

有時候,經過一個名稱來標識一個路由顯得更方便一些,特別是在連接一個路由,或者是執行一些跳轉的時候。你能夠在建立 Router 實例的時候,在 routes 配置中給某個路由設置名稱。

const router = new VueRouter({
  routes: [
    {
      path: '/user/:userId',
      name: 'user',
      component: User
    }
  ]
})

 

要連接到一個命名路由,能夠給 router-link 的 to 屬性傳一個對象:

<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>

 

這跟代碼調用 router.push() 是一回事:

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

 

這兩種方式都會把路由導航到 /user/123 路徑。

完整的例子請移步這裏

嵌套路由

嵌套路由跟普通路由基本沒有什麼區別。可是可讓 vue 開發變的很是靈活。 官網這塊寫的也很是好,我就直接拷貝了(原諒我吧。) 實際生活中的應用界面,一般由多層嵌套的組件組合而成。一樣地,URL 中各段動態路徑也按某種結構對應嵌套的各層組件,例如:

/user/foo/profile                     /user/foo/posts
+------------------+                  +-----------------+
| User             |                  | User            |
| +--------------+ |                  | +-------------+ |
| | Profile      | |  +------------>  | | Posts       | |
| |              | |                  | |             | |
| +--------------+ |                  | +-------------+ |
+------------------+                  +-----------------+
藉助 vue-router,使用嵌套路由配置,就能夠很簡單地表達這種關係。
<div id="app">
  <router-view></router-view>
</div>
const User = {
  template: '<div>User {{ $route.params.id }}</div>'
}

const router = new VueRouter({
  routes: [
    { path: '/user/:id', component: User }
  ]
})
這裏的 <router-view> 是最頂層的出口,渲染最高級路由匹配到的組件。一樣地,一個被渲染組件一樣能夠包含本身的嵌套 <router-view>。例如,在 User 組件的模板添加一個 <router-view>:

const User = {
  template: `
    <div class="user">
      <h2>User {{ $route.params.id }}</h2>
      <router-view></router-view>
    </div>
  `
}
要在嵌套的出口中渲染組件,須要在 VueRouter 的參數中使用 children 配置:

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

 

要注意,以 / 開頭的嵌套路徑會被看成根路徑。 這讓你充分的使用嵌套組件而無須設置嵌套的路徑。 你會發現,children 配置就是像 routes 配置同樣的路由配置數組,因此呢,你能夠嵌套多層路由。

此時,基於上面的配置,當你訪問 /user/foo 時,User 的出口是不會渲染任何東西,這是由於沒有匹配到合適的子路由。若是你想要渲染點什麼,能夠提供一個 空的 子路由:

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

        // ...其餘子路由
      ]
    }
  ]
});

 

命名視圖

有時候想同時(同級)展現多個視圖,而不是嵌套展現,例如建立一個佈局,有 sidebar(側導航) 和 main(主內容) 兩個視圖,這個時候命名視圖就派上用場了。你能夠在界面中擁有多個單獨命名的視圖,而不是隻有一個單獨的出口。若是 router-view 沒有設置名字,那麼默認爲 default

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

 

一個視圖使用一個組件渲染,所以對於同個路由,多個視圖就須要多個組件。確保正確使用 components 配置(帶上 s):

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

 

以上案例相關的可運行代碼請移步這裏

嵌套命名視圖

咱們也有可能使用命名視圖建立嵌套視圖的複雜佈局。這時你也須要命名用到的嵌套 router-view 組件。咱們以一個設置面板爲例:

/settings/emails                                       /settings/profile
+-----------------------------------+                  +------------------------------+
| UserSettings                      |                  | UserSettings                 |
| +-----+-------------------------+ |                  | +-----+--------------------+ |
| | Nav | UserEmailsSubscriptions | |  +------------>  | | Nav | UserProfile        | |
| |     +-------------------------+ |                  | |     +--------------------+ |
| |     |                         | |                  | |     | UserProfilePreview | |
| +-----+-------------------------+ |                  | +-----+--------------------+ |
+-----------------------------------+                  +------------------------------+
  • Nav 只是一個常規組件。
  • UserSettings 是一個視圖組件。
  • UserEmailsSubscriptionsUserProfileUserProfilePreview 是嵌套的視圖組件。

注意:咱們先忘記 HTML/CSS 具體的佈局的樣子,只專一在用到的組件上

UserSettings 組件的 <template> 部分應該是相似下面的這段代碼:

<!-- UserSettings.vue -->
<div>
  <h1>User Settings</h1>
  <NavBar/>
  <router-view/>
  <router-view name="helper"/>
</div>

 

嵌套的視圖組件在此已經被忽略了,可是你能夠在這裏找到完整的源代碼

而後你能夠用這個路由配置完成該佈局:

{
  path: '/settings',
  // 你也能夠在頂級路由就配置命名視圖
  component: UserSettings,
  children: [{
    path: 'emails',
    component: UserEmailsSubscriptions
  }, {
    path: 'profile',
    components: {
      default: UserProfile,
      helper: UserProfilePreview
    }
  }]
}

 

一個能夠工做的示例的 demo 在這裏

路由組件傳參

在組件中使用 $route 會使之與其對應路由造成高度耦合,從而使組件只能在某些特定的 URL 上使用,限制了其靈活性。

使用 props 將組件和路由解耦:

取代與 $route 的耦合

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

 

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

布爾模式

若是 props 被設置爲 trueroute.params 將會被設置爲組件屬性。

對象模式

若是 props 是一個對象,它會被按原樣設置爲組件屬性。當 props 是靜態的時候有用。

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

 

函數模式

你能夠建立一個函數返回 props。這樣你即可以將參數轉換成另外一種類型,將靜態值與基於路由的值結合等等。

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

 

URL /search?q=vue 會將 {query: 'vue'} 做爲屬性傳遞給 SearchUser 組件。

請儘量保持 props 函數爲無狀態的,由於它只會在路由發生變化時起做用。若是你須要狀態來定義 props,請使用包裝組件,這樣 Vue 才能夠對狀態變化作出反應。

更多高級用法,請查看例子

導航守衛

(譯者:『導航』表示路由正在發生改變。)

正如其名,vue-router 提供的導航守衛主要用來經過跳轉或取消的方式守衛導航。有多種機會植入路由導航過程當中:全局的, 單個路由獨享的, 或者組件級的。

記住參數或查詢的改變並不會觸發進入/離開的導航守衛。你能夠經過觀察 $route 對象來應對這些變化,或使用 beforeRouteUpdate 的組件內守衛。

全局守衛

你可使用 router.beforeEach 註冊一個全局前置守衛:

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

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

 

當一個導航觸發時,全局前置守衛按照建立順序調用。守衛是異步解析執行,此時導航在全部守衛 resolve 完以前一直處於 等待中。

每一個守衛方法接收三個參數:

  • to: Route: 即將要進入的目標 路由對象

  • from: Route: 當前導航正要離開的路由

  • next: Function: 必定要調用該方法來 resolve 這個鉤子。執行效果依賴 next 方法的調用參數。

    • next(): 進行管道中的下一個鉤子。若是所有鉤子執行完了,則導航的狀態就是 confirmed (確認的)。

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

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

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

確保要調用 next 方法,不然鉤子就不會被 resolved。

全局解析守衛

2.5.0 新增

在 2.5.0+ 你能夠用 router.beforeResolve 註冊一個全局守衛。這和 router.beforeEach 相似,區別是在導航被確認以前,同時在全部組件內守衛和異步路由組件被解析以後,解析守衛就被調用。

全局後置鉤子

你也能夠註冊全局後置鉤子,然而和守衛不一樣的是,這些鉤子不會接受 next 函數也不會改變導航自己:

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

 

路由獨享的守衛

你能夠在路由配置上直接定義 beforeEnter 守衛:

const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        // ...
      }
    }
  ]
})

 

這些守衛與全局前置守衛的方法參數是同樣的。

組件內的守衛

最後,你能夠在路由組件內直接定義如下路由導航守衛:

  • 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,由於守衛在導航確認前被調用,所以即將登場的新組件還沒被建立。

不過,你能夠經過傳一個回調給 next來訪問組件實例。在導航被確認的時候執行回調,而且把組件實例做爲回調方法的參數。

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

 

注意 beforeRouteEnter 是支持給 next 傳遞迴調的惟一守衛。對於 beforeRouteUpdate 和 beforeRouteLeave 來講,this 已經可用了,因此不支持傳遞迴調,由於沒有必要了。

beforeRouteUpdate (to, from, next) {
  // just use `this`
  this.name = to.params.name
  next()
}

 

這個離開守衛一般用來禁止用戶在還未保存修改前忽然離開。該導航能夠經過 next(false) 來取消。

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 的回調函數。

過渡動效

<router-view> 是基本的動態組件,因此咱們能夠用 <transition> 組件給它添加一些過渡效果:

<transition>
  <router-view></router-view>
</transition>

 

<transition> 的全部功能 在這裏一樣適用。

單個路由的過渡

上面的用法會給全部路由設置同樣的過渡效果,若是你想讓每一個路由組件有各自的過渡效果,能夠在各路由組件內使用 <transition> 並設置不一樣的 name。

const Foo = {
  template: `
    <transition name="slide">
      <div class="foo">...</div>
    </transition>
  `
}

const Bar = {
  template: `
    <transition name="fade">
      <div class="bar">...</div>
    </transition>
  `
}

 

基於路由的動態過渡

還能夠基於當前路由與目標路由的變化關係,動態設置過渡效果:

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

 

// 接着在父組件內
// watch $route 決定使用哪一種過渡
watch: {
  '$route' (to, from) {
    const toDepth = to.path.split('/').length
    const fromDepth = from.path.split('/').length
    this.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left'
  }
}

 

查看完整例子請移步這裏

總結

其實做爲入門的話,暫時先掌握這些知識,後續

相關文章
相關標籤/搜索