# Vue Router

## vue Router的两种路由模式

### **hash模式**

* 改变#后面的hash值，会触发onhashchange事件，在该事件里对页面进行局部操作
* hash的变化会被浏览器记录（历史访问栈）下来，可以前进、后退、刷新而不向服务器发送请求
* 通过匹配#后面的hash，与vueRouter配置文件里的path对应做路由跳转

### **history模式**

* 基于浏览器history的pushState()、replaceState()、popState()来实现，可以读取、修改浏览器历史记录栈
* 可以前进、后退不发往服务器发送请求，但刷新会向服务器发送请求
* 若匹配不到资源，则返回404，因此需要后台支持，重定向到根目录主页

## 动态路由匹配

> 通过不同参数，来匹配到同一组件

比如我们有一个通用的文章详情页，需要通过不同的文章id来显示不同的内容，则我们可以通过 **article:id** 来完成

### **$route.params**

> 一个 key/value 对象，包含了动态片段和全匹配片段

article/:id 转换为> $route.params.id

article/123 => $route.params.id = 123

![](https://user-gold-cdn.xitu.io/2019/4/29/16a6861e5af2c976?imageView2/0/w/1280/h/960/format/webp/ignore-error/1)

### **$route.query**

> 一个 key/value 对象，表示 URL 查询参数

`article?id='123' => $route.params.id = '123'`

![](https://user-gold-cdn.xitu.io/2019/4/29/16a686783be2c511?imageView2/0/w/1280/h/960/format/webp/ignore-error/1)

## 导航守卫

**注意！改变路由的参数不会触发进入/离开的导航守卫**

* 使用watch监听$route
* 使用组件内守卫beforeRouteUpdate来监听变化

### 全局守卫

**全局前置守卫< beforeEach >**

> 当导航被触发时会被调用，守卫是异步解析执行的，当守卫未resolved之前，导航一直处于等待

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

* 可以在此阶段做权限校验

**全局解析守卫< beforeResolve >**

当导航被确认同时组件内守卫和异步守卫都解析后触发

**全局后置钩子< afterEach >**

> 导航跳转完成后被触发

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

### 路由独享守卫

**beforeEnter**

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

### 组件内守卫

> 仅限在组件内定义使用

**beforeRouteEnter**

```
 beforeRouteEnter (to, from, next) {
    // 不！能！获取组件实例 `this`
    // 因为当守卫执行前，组件实例还没被创建
}
```

* 在渲染该组件对应路由被确认前调用
* 在此阶段无法访问this，因为守卫在导航确认前被调用，此时组件还未被创建
* 可以通过给next设置回调来访问this

```
beforeRouteEnter (to, from, next) {
    next(vm => {
        通过vm访问组件实例
    })
}
```

**beforeRouteUpdate**

```
beforeRouteUpdate (to, from, next) {
    // 可以访问this
    this.name = to.params.name // 可以获取路由参数
    next()
}
```

* 当导航路由发生改变，组件被复用时触发
* 复用组件时无法触发进入、离开的导航守卫
* 给路由传参会触发此守卫

**beforeRouteLeave**

```
beforeRouteLeave (to, from, next) {
    const answer = window.confirm('Do you really want to leave? you have unsaved changes!')
    if (answer) {
        next()
    } else {
        next(false) // 可通过此方法取消导航
    }
}
```

* 当离开此导航路由时触发
* 一般用于禁止用户还未保存修改前离开
