vue2.x 路由

2020/7/29 vue

# 开始使用

import Vue from 'vue'
import VueRouter from 'vue-router'

const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }

const routes = [
  { path: '/foo', component: Foo },
  { path: '/bar', component: Bar }
]

const router = new VueRouter({
  routes
})

const app = new Vue({
  router
}).$mount('#app')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 全局路由钩子

  • beforeEach
router.beforeEach((to, from, next) => {
  //一般登录拦截用这个,也叫导航钩子守卫
  if (path === '/login') {
    next()
    return
  }
  if (token) {
    next();
  }
})

// beforeResolve

// afterEach
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 组件路由钩子

  • beforeRouteEnter
beforeRouteEnter (to, from, next) {
  // 这里还无法访问到组件实例,this === undefined
  next( vm => {
    // 通过 `vm` 访问组件实例
  })
}

// beforeRouteUpdate

// beforeRouteLeave
1
2
3
4
5
6
7
8
9
10

# Vue.$router

// 跳转到不同的url,但这个方法回向history栈添加一个记录,点击后退会返回到上一个页面
this.$router.push()
// 不会有记录
this.$router.replace()
// n可为正数可为负数。正数返回上一个页面,类似 window.history.go(n)
this.$router.go(n)
1
2
3
4
5
6

# Vue.$route

// 获取通过 params 或/:id传参的参数
this.$route.params.id

// 获取通过 query 传参的参数
this.$route.query.id
1
2
3
4
5

# router render

component: {
  render: h => h("router-view");
}
1
2
3

# 路由传参

  • 方式一
// 路由定义
{
  path: '/describe/:id',
  name: 'Describe',
  component: Describe
}
// 页面传参
this.$router.push({
  path: `/describe/${id}`,
})
// 页面获取
this.$route.params.id
1
2
3
4
5
6
7
8
9
10
11
12
  • 方式二
// 路由定义
{
  path: '/describe',
  name: 'Describe',
  component: Describe
}
// 页面传参
this.$router.push({
  name: 'Describe',
  params: {
    id: id
  }
})
// 页面获取
this.$route.params.id
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  • 方式三
// 路由定义
{
  path: '/describe',
  name: 'Describe',
  component: Describe
}
// 页面传参
this.$router.push({
  path: '/describe',
    query: {
      id: id
  }
)
// 页面获取
this.$route.query.id
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 路由拆分

  • 目录
# router
├── router
│   ├── index.js
│   └── router.js

# views目录下
views
├── Page
│   ├── api.js # 接口定义
│   ├── router.js # 路由配置
│   └── src
│       └── layered
│           ├── detail.vue
│           ├── index.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  • src/router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import routes from './router'

Vue.use(VueRouter)

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

export default router
1
2
3
4
5
6
7
8
9
10
11
12
  • src/router/router.js
// 利用 webpack 读取 views 目录下的 router.js
const routerFile = require.context('../', true, /^\.\/views\/[\w.-]+\/router.js$/)

// 返回的 routerFile.keys() 是一个路由配置的路径数组列表 ['./views/Page/router.js']
// 循环递归调用 routerFile 去解析 每一项的路径地址 './views/Page/router.js'
// 返回 文件内容: Module { default: { path: "/page", name: 'xxx', children:[{},...]}, ... }

// 获取返回路由集合
const routesConfig = (r => {
  return r.keys().map(key => r(key).default)
})(routerFile)

// redirect
const redirectConfig = {
  path: '*',
  redirect: '/'
}

const routes = routesConfig.concat(redirectConfig)
return routes
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  • src/views/Page/router.js
export default {
  path: '/page',
  name: 'Page',
  component: () => import('@/components/RouterCache.vue'),
  meta: {
    keepAlive: true,
    title: 'Page A',
  },
  children: [
    {
      path: 'detail/:id',
      name: 'PageDetail',
      component: () => import('./src/detail/index.vue'),
      meta: {
        keepAlive: true,
      }
    }
  ]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 缓存和动画

<transition>
  <keep-alive :include="['a', 'b']">
  //或include="a,b" :include="/a|b/",a 和 b 表示组件的 name
  //因为有些页面,如试试数据统计,要实时刷新,所以就不需要缓存
    <router-view/> //路由标签
  </keep-alive>
  <router-view exclude="c"/>
  // c 表示组件的 name值
</transition>
1
2
3
4
5
6
7
8
9
  • Cached Router: RouterCache.vue
<template>
  <div>
    <keep-alive>
      <router-view v-if="$route.meta.keepAlive" />
    </keep-alive>
    <router-view v-if="!$route.meta.keepAlive" />
  </div>
</template>

<script>
export default {
  name: 'RouterCache'
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# router-view 的 key

//  Vue 会复用相同组件, key可以解决 组件的 created 和 mounted 不调用问题
<router-view :key="$route.fullPath"></router-view>
1
2

# vue-router3.x错误拦截

import Vue from 'vue'
import VueRouter from 'vue-router'
import routes from './routes'

Vue.use(VueRouter)
// 隐藏vue-router在3.0版本控制台错误信息(跳转相同路径会报错)
const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function(location) {
  return originalPush.call(this, location).catch(err => err)
}
const originalReplace = VueRouter.prototype.replace
VueRouter.prototype.replace = function(location) {
  return originalReplace.call(this, location).catch(err => err)
}

const router = new VueRouter({
  mode: 'history',
  base: process.env.VUE_APP_HASH ? '/' : process.env.BASE_URL,
  routes
})

export default router
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# router全局添加query参数

// 全局添加biz query参数: 仅限于vue-router
const QUERY_BIZID_NAME = 'bizid'
export const addRouterBizQuery = (router) => {
  router.beforeEach((to, from, next) => {
    const bizId = to.query[QUERY_BIZID_NAME]
    const curId = getCurrentBizId()
    if (!bizId || !isValidBizId(bizId) || bizId !== curId) {
      const query = {
        ...to.query,
        [QUERY_BIZID_NAME]: curId
      }
      next &&
        next({
          ...to,
          query: query
        })
    } else {
      next && next()
    }
  })
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21