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

 

查看完整例子请移步这里

总结

其实做为入门的话,暂时先掌握这些知识,后续

相关文章
相关标签/搜索