1小时 Vue Router 从入门到放弃

​ 本文所用项目 GitHub 地址:https://github.com/trp1119/vue-router

​ 本文与 Vue Router 官方文档 区别:非官方文档功能罗列,而是从实际应用角度一步步进行 Vue Router 设置及功能介绍。水平有限,难免存有纰漏,欢迎在评论区指正交流。

前言

​ 现在做前端 Web App,路由是必不可缺的功能。以前网站开发,由链接跳转到后端,进行模板渲染,产生一个新的 HTML 返回给浏览器端,等浏览器显示出页面,完成一次路由跳转。而对于现在的单页面应用开发,页面跳转不经过后端服务器,页面渲染内容全部来自于JavaScript。既然路由跳转由前端来做,则需要称职合理的工具处理前端路由。

​ 现在基本上每个前端框架都会配备路由管理工具,像 Vue 使用的 Vue RouterReact 使用的 React Router,还有不和框架耦合的 History 等工具。这些工具,在前端 SAP 开发中起着越来越重要的作用。

​ 什么是 Vue RouterVue RouterVue.js 官方的路由管理器。通过将组件映射到路由 routes,然后使用 Vue Router 进行渲染,实现路由功能。

​ 本文 Vue Router 基于模块化工程使用。在使用之前,需要先安装 vue-router 插件。

npm i vue-router -S
1 Vue Router 之集成

vue-router 插件安装完毕后,需要进行路由的部署。在 src 文件夹下 创建 router 文件夹并创建 router.jsroutes.js 文件。

​ 为什么分开配置?因为在项目变庞大之后,路由配置会非常多,所以可以单独配置一个和路由映射关系有关的文件 routes.js,而 router.js 主要进行路由器 router 的内容配置。

1.1 在 routes.js 中配置路由映射关系

export default 一个数组,数组中的每个对象都是一个路由项。

import Login from '../view/login' // 1.引入组件
import Home from '../view/home'

export default [ // 4.导出路由映射关系
  {
    path: '/login', // 2.设置跳转路由
    component: Login // 3.映射组件
  },
  {
    path: '/home',
    component: Home
  }
]

​ 不推荐这么使用,因为这样每次在全局 import这个 router 的时候,引入的都是同一个 router,如果需要每次引入的时候新创建一个 router,这种方式是做不到的。

​ 另外,由于项目需要服务端渲染。每次 export default 同一个 router,会导致在服务端渲染时出现内存溢出的问题。每次服务端渲染都会重新生成一个新的 app,由于 router 只有一个对象(共用同一个),在服务端渲染流程结束后,app 对象没有释放,每次都会缓存新的 app,导致内存没有下降,一直处于高点,随着内存逐渐累加,出现内存溢出。

1.2 默认路由跳转

​ 在路由配置文件 routes.js 中配置默认路由跳转。

export default [
  {
    path: '/', // 根路径
    redirect: '/login' // 默认跳转路由
  },
  {
    path: '/login',
    component: Login
  },
  {
    path: '/home',
    component: Home
  }
]
1.3 在 route.js 中配置路由器

1.3.1 配置方法1

import Router from 'vue-router' // 1.引入 Vue Router 插件中 Router 路由器
import routes from './routes' // 2.引入路由映射关系

export default new Router({ // 4.创建并导出 Router 对象实例
  routes // 3.传入映射关系配置
})

1.3.2 配置方法2

import Router from 'vue-router' // 1.引入 Vue Router 插件中 Router 路由器
import routes from './routes' // 2.引入路由映射关系

export default () => { // 4.创建并导出 Router 方法(注意这里导出的是方法,并没有在此创建对象实例)
  return new Router({
    routes // 3.传入映射关系配置
  })
}

​ 每次生成新的 Router 对象实例,渲染结束同 app 一起释放,不会出现内存溢出问题。

1.4 在入口文件 main.js 中注入路由功能

​ 引入 VueRouter 插件并使用(Vue.use())以使用路由功能,引入前面配置好的 Router 方法并使用以使用路由设置及映射关系。

import Vue from 'vue'
import VueRouter from 'vue-router' // 引入 VueRouter 路由插件

import App from './App.vue'

import createRouter from './router/router' // 引入带映射关系的 Router 方法

Vue.config.productionTip = false

Vue.use(VueRouter) // 使用 VueRouter 插件
const router = createRouter() // 在此创建 router 对象

new Vue({
  router, // 注入路由。通过在根节点 Vue 实例上挂载 router 对象,使每个组件都能拿到这个 router 对象,从而让整个应用都有路由功能。(VueRouter内部实现此功能)
  render: h => h(App),
}).$mount('#app')
1.5 使用 router-view 渲染匹配到的组件

​ 在 App.js 中渲染页面。

<template>
  <div id="app">
   <!-- 路由出口 -->
   <!-- 路由匹配到的组件将渲染在这里 -->
    <router-view />
  </div>
</template>
1.6 使用 router-link 进行页面跳转

​ router-link 的实现是 a 标签。点击对应链接后会在 <router-view /> 中渲染路由匹配到的组件。

​ 页面中可点击的路由一般都会通过 router-link,因为 router-link 的实现是 a 标签,a 标签中的 href 有利于网站的 SEO,但 a 标签默认的行为是页面跳转,而不是前端路由跳转。即 router-link 不单纯是 a 标签的实现,而是通过内部事件,实现前端路由跳转。

<template>
  <div id="app">
    <router-link to="/login">去Login页</router-link>
    <router-link to="/home">去Home页</router-link>
    <!-- 组件渲染 -->
    <router-view />
  </div>
</template>
1-6.png
1.7 Vue Router 基础集成设置完毕

​ 设置完毕,在页面打开路由。可以发现 Vue Router 自动在网站域名后添加了 #/ ,这是因为 Vue Router 默认的路由形式是使用哈希路由。作为 SAP 且有服务端渲染的情况下,路由改为 histiory 形式(无 #/)更为合理且更利于 SEO 优化。

1-7.png
2 Vue Router 之配置

​ 创建 router 实例时常用参数配置及作用。

2.1 mode配置

Vue Router 默认使用哈希路由(路由中带 #),但哈希路由一般用来定位,而不是做路由状态的记录。同时,哈希路由不会被搜索引擎解析,影响网站 SEO 。所以在服务端渲染时,一般不使用哈西路由。

​ 使用 history 路由,可在路由器配置文件 route.js 中配置 modemode 有两种参数,一个是默认的 hash ,一个是 history

export default () => {
  return new Router({
    routes, // 路由配置项
    // mode: 'hash', // 默认哈西路由 
    mode:'history',  // 配置 hisyory 路由
  })
}
2-1-1.png
2-1-2.png
2.2 base 配置

​ 在 routes.js 配置的所有路由前天添加 /自定义base/,这个路径作为所有应用的基路径。在应用中不论是用 route-link 还是 route 对象跳转,只要是通过 vue routerapi 跳转,都会加上此基路径。但是把路径中 /base/ 手动去掉,仍然会显示,所有 base 不是强制性的。在区分页面路径和其他类型路径的时候会用到。

​ 在 mode 配置为 hash 时,base 配置不生效。

export default () => {
  return new Router({
    routes,
    mode:'history',
    base: '/mybase/', // 注意加前后/,base 在 mode 配置为 hash 时不生效
  })
}
2.3 linkActiveClass 与 linkExactActiveClass 配置

​ 查看 1.5 中配置的 route-link 浏览器解析源码,会发现激活的路由默认添加 router-link-exact-activerouter-link-active 样式,可以在 linkActiveClasslinkExactActiveClass 中自定义样式名称,然后在 css 中自定义全局样式。

2-3-1.png
export default () => {
  return new Router({
    routes,
    mode:'history',
    base: '/mybase/',
    linkActiveClass: 'active-link', // 配置 route-link 链接 class,路径不完全匹配时添加 class 为 linkActiveClass
    linkExactActiveClass: 'exact-active-link', // 路径完全匹配时添加 class 为 linkExactActiveClass linkActiveClass
  })
}

​ 配置完毕,可以看到 a 标签 class 样式已经变为配置样式。

2-3-2.png

​ 那么 linkActiveClasslinkExactActiveClass 有什么区别?

​ 展示区别前,先在 routes.jsapp.vue 中补充路由。

// routes.js
export default [
  {
    path: '/',
    redirect: '/login'
  },
  {
    path: '/login',
    component: Login
  },
  {
    path: '/home',
    component: Home
  },
  {
    path: '/home/exact', // 补充路由
    component: Home
  }
]
<!-- app.vue -->
<template>
  <div id="app">
    <router-link to="/login">去Login页</router-link>
    <router-link to="/home">去Home页</router-link>
    <!-- 补充链接 -->
    <router-link to="/home/exact">去Home/exact页</router-link>
    <!-- 组件渲染 -->
    <router-view />
  </div>
</template>

​ 补充完毕,点击“去Home/exact页”后,查看浏览器源码,会发现 “去Home页”路由少了 my-exact-active-link 样式,但仍保留 my-active-link 样式。即路径不完全匹配时添加 class 为 my-active-linklinkActiveClass 中配置的样式),路径完全匹配时添加 class 为 my-exact-active-link my-active-linklinkExactActiveClasslinkActiveClass 中配置的样式)。

2-3-3.png
2.4 scrollBehavior 配置

scrollBehavior 用于配置页面跳转时是否滚动,scrollBehavior 接收一个方法,有三个参数 tofromsavePosition,其中,参数 to 为去的路由,from 跳转到 to 路由之前的路由。如果之前进入过这个路由,savePosition 用于保存之前滚动条滚动的位置。tofrom 不是字符串,而是完整的 router 的对象,包含路由的 paramsquery 等信息。

export default () => {
  return new Router({
    routes,
    mode:'history',
    base: '/mybase/',
    linkActiveClass: 'active-link',
    linkExactActiveClass: 'exact-active-link',
    scrollBehavior (to, from, savePosition) { // 页面跳转时是否需要滚动
      // to 去往路由 from 来时路由 savePosition 记录滚动条位置
      if (savePosition) {
        return savePosition // 如果进入过,回到之前的位置
      } else {
        return { x: 0, y: 0 } // 如果未因如果,滚动到原点
      }
    },
  })
}
2.5 parseQuery 与 stringifyQuery

​ 例如 http://localhost/login?name=zhangsan&password=12345url 后带的参数 queryname=zhangsan&password=12345string 格式,需转为 JSON Object,Vue 是默认做转换的,但如果有默认需求,可通过配置 parseQuery 进行转换。将 Object 转为 stiring 可在 stringifyQuery 中配置。

export default () => {
  return new Router({
    routes,
    mode:'history',
    base: '/mybase/',
    linkActiveClass: 'active-link',
    linkExactActiveClass: 'exact-active-link',
    scrollBehavior (to, from, savePosition) {
      if (savePosition) {
        return savePosition
      } else {
        return { x: 0, y: 0 }
      }
    },
    parseQuery (query) {},
    stringifyQuery (obj) {},
  })
}
2.6 fallback配置

​ 并不是所有浏览器都支持 history 前端路由(页面不跳转但内容切换),在不支持 history 前端路由的浏览器中,Vue 自动 fallback hash 路由模式,如果不希望 Vue 进行此操作,可将 fallback 设置为 false。当 fallbackfalse 时,Vue 不会去自动处理,在不支持 histiory 路由的浏览器中,单页面应用就变为多页面应用,每次页面跳转都会去后端请求数据返回内容,耗时。

export default () => {
  return new Router({
    routes,
    mode:'history',
    base: '/mybase/',
    linkActiveClass: 'active-link',
    linkExactActiveClass: 'exact-active-link',
    scrollBehavior (to, from, savePosition) {
      if (savePosition) {
        return savePosition
      } else {
        return { x: 0, y: 0 }
      }
    },
    parseQuery (query) {},
    stringifyQuery (obj) {},
    fallback: true,
  })
}
3 route 配置及参数传递
3.1 name 配置

​ 使用 name 对路由进行命名,和 pathcomponent 的命名无关联,可以使用这个 name 进行路由跳转。

// routes.js
export default [
  //...
  {
    path: '/login',
    component: Login,
    name: Login, // name 命名
  },
  //...
]

​ 在路由跳转配置中,name 传入的是 JSON Object,希望 Vue 去解析它而不是当做 stirng 处理,所以需要使用 v-bind 进行数据绑定

<!-- app.vue -->
<template>
  <div id="app">
    <router-link to="/login">去Login页</router-link>
   <!-- name 形式路由 -->
    <router-link :to="{name: 'login'}">去Login页(name 形式)</router-link> 
    <router-link to="/home">去Home页</router-link>
    <router-link to="/home/exact">去Home/exact页</router-link>
    <!-- 组件渲染 -->
    <router-view />
  </div>
</template>
3.2 meta 配置

meta 用于保存路由信息,

​ 在 html head 标签中会使用 meta 保存页面元信息,这些信息有利于 SEO 优化。在写 Vue 组件的时候,很难写入这些信息,则可在路由配置中加入 meta,这些信息,可以在拿到路由 route 对象时通过 .mate 拿到这些信息并进行设置。

// routes.js
export default [
  //...
  {
    path: '/login',
    component: Login,
    name: Login,
    meta: { // meta 配置
      title: 'This is Home Page',
      description: 'This is Home Page description'
    },
  },
  //...
]
3.3 children 嵌套路由配置

children 也是个数组,是子路由,配置和父级路由配置相同。

// routes.js
export default [
  //...
  {
    path: '/login',
    component: Login,
    name: Login,
    meta: { // meta 配置
      title: 'This is Login Page',
      description: 'This is Login Page description'
    },
    children: [ // 子路由(嵌套路由),路由匹配的内容都是通过 <route-view />展示的,/login 下的 children子路由,则其 <route-view /> 在父级路由组件 Login 中显示。
      {
        path: 'loginChild',
        component: () => import('../view/loginChild')
      }
    ],
  },
  //...
]

​ 在 login.vue 中加入 <route-view />

<!-- login.vue -->
<template>
  <div>
    <div>Login页内容</div>
    <!-- 展示子路由内容 -->
    <router-view /> 
  </div>
</template>
3-3.png
3.4 transition 过渡动画

​ 使用 transition 包裹 <router-view /> ,并进行动画样式设置。如果包裹根页面(App.vue)中的 <router-view />,会为每个路由切换都添加过渡动画。想要某个页面使用切换效果,使用 transition 包裹单个组件的 <router-view /> 即可。

<!-- app.vue-->
<template>
  <div id="app">
    <router-link to="/login">去Login页</router-link>
    <router-link :to="{name: 'login'}">去Login页(name 形式)</router-link>
    <router-link to="/home">去Home页</router-link>
    <router-link to="/home/exact">去Home/exact页</router-link>
    <!-- 路由动画-->
    <transition name="fade">
      <router-view />
    </transition>
  </div>
</template>

<!-- ...-->

<style>
/*
    ...
*/
/*动画样式设置*/
/* fade为自己命名的name,后缀为Vue要求写法 */
.fade-enter-active .fade-leave-active {
  transition: opacity .5s;
}
.fade-enter .fade-leave-to {
  opacity: 0;
}
</style>
3.5 :id 动态传参

path: '/login/:id',动态绑定 id,当页面路径为 /login/123 时,则 id123,在页面中通过 this.$route.params 可以拿到键值对。

// routes.js
export default [
  //...
  {
    path: '/login/:id',
    component: Login,
    name: Login,
    meta: {
      title: 'This is Login Page',
      description: 'This is Login Page description'
    },
    children: [
      {
        path: 'loginChild',
        component: () => import('../view/loginChild')
      }
    ],
  },
  //...
]
<!-- app.vue-->
<template>
  <div id="app">
    <!-- 路由中的 id 及为链接中的 123-->
    <router-link to="/login/123">Login123</router-link>
    <router-link to="/login">去Login页</router-link>
    <router-link :to="{name: 'login'}">去Login页(name 形式)</router-link>
    <router-link to="/home">去Home页</router-link>
    <router-link to="/home/exact">去Home/exact页</router-link>
    <transition name="fade">
      <router-view />
    </transition>
  </div>
</template>

<script>
export default {
  mounted () {
    console.log(this.$route) //打印 this.$route 对象
  }
}
</script>

​ 页面路径 http://localhost:8080/mybase/login/123?name=zhangsan&password=123456

this.$route 对象打印结果:

3-5.png

​ 可以看出,路由 path 中不会出现 router.js 中设置的 base,参数以 json 对象的形式存放在 query 中。

3.6 props

​ 定义 propstrue 后,可以将 :id 作为 props 传入组件 Login 中,即在组件中,用 props 直接接收即可, props: ['id'],代替父组件传值。这种方式可以实现在组件内不需要写 this.$route 而用 props 直接接收。

​ 如果组件中写了 this.$route 这种写法,路由与组件耦合在一起,组件就不能单独拿去复用(因为组件绑定了路由),可能会存在路由不匹配。如果用 props 声明,在其他地方也可以使用这个组件,因为 依赖的 id 值可以改为通过父组件传入,不再依赖路由读取,实现解耦。

// routes.js
export default [
  //...
  {
    path: '/login/:id',
    props: true,
    component: Login,
    name: Login,
    meta: {
      title: 'This is Login Page',
      description: 'This is Login Page description'
    },
    children: [
      {
        path: 'loginChild',
        component: () => import('../view/loginChild')
      }
    ],
  },
  //...
]
<!-- login.vue -->
<template>
  <div>
    <div>Login页内容</div>
    <router-view />
  </div>
</template>

<script>
export default {
  props: ['id'],
  mounted () {
    console.log(this.id) // 可以直接在控制台打印出 123
  }
}
</script>

​ 路由中 props 配置除了从 path 中取参数,也可以自己定义内容,这时,页面 props 中接收的内容即为 路由 props 中设置的值。

// routes.js
export default [
  //...
  {
    path: '/login/:id',
    props: {
      id: '456',
      sex: 'man'
    },
    component: Login,
    name: Login,
    meta: {
      title: 'This is Login Page',
      description: 'This is Login Page description'
    },
    children: [
      {
        path: 'loginChild',
        component: () => import('../view/loginChild')
      }
    ],
  },
  //...
]
<!-- login.vue -->
<template>
  <div>
    <div>Login页内容</div>
    <router-view />
  </div>
</template>

<script>
export default {
  props: ['id', 'sex'],
  mounted () {
    console.log(this.id, this.sex) // 可以直接在控制台打印出 456 ,man
  }
}
</script>

​ 路由 props 也可以从路由中取值,例如取路由 query 中的值,这样,页面就无需采用 this.$route.query.xxx 方式去取值。

// routes.js
export default [
  //...
  {
    path: '/login/:id',
    props: (route) => ({name:route,query.name}), // 这里的 route 相当于组件中的 this.$route
    component: Login,
    name: Login,
    meta: {
      title: 'This is Login Page',
      description: 'This is Login Page description'
    },
    children: [
      {
        path: 'loginChild',
        component: () => import('../view/loginChild')
      }
    ],
  },
  //...
]

​ 推荐不要拘泥于 this.$route 写法,尽量实现组件与路由解耦,以提高组件复用性。

4 高级功能
4.1 命名视图

​ 前面写的一个页面中只有一个路由出口 <route-view />,但如果同一个页面中有两部分,在不同的路由下显示不同的内容,这时可在同一个组件内部使用两个 <route-view /> ,并对其进行命名,对于不同的 <route-view />,在不同的名字下赋予不同的组件。

​ 在路由项配置文件 routes.js 中,使用 components 分配不同的组件。

// routes.js
export default [
  //...
  {
    path: '/login/:id',
    props: {
      id: '456',
      sex: 'man'
    },
    components: {
        default: Login, // 未命名,默认使用 default
        myRouteView: Home // 不可采用 my-route-view 形式
    },
    name: Login,
    meta: {
      title: 'This is Login Page',
      description: 'This is Login Page description'
    },
    children: [
      {
        path: 'loginChild',
        component: () => import('../view/loginChild')
      }
    ],
  },
  //...
]
<!-- app.vue-->
<template>
  <div id="app">
    <router-link to="/login/123">Login123</router-link>
    <router-link to="/login">去Login页</router-link>
    <router-link :to="{name: 'login'}">去Login页(name 形式)</router-link>
    <router-link to="/home">去Home页</router-link>
    <router-link to="/home/exact">去Home/exact页</router-link>
    <transition name="fade">
      <router-view />
    </transition>
    <!-- 注意:transition 只能包裹单页元素,不可两个 router-view 在同一个 transition 内 -->
    <!-- 不同名字的 <router-view /> -->
    <!-- 不可采用 my-route-view 形式 -->
    <router-view name="myRouteView" /> 
  </div>
</template>
4-1.png
4.2 导航守卫(导航钩子)

4.2.1 全局导航守卫

main.js 中进行全局导航守卫注册。可以用 beforeEach 验证用户是否登录,如果未登录,自动跳转至登录页面。next() 中参数配置同 route-link 中参数配置。

必须执行 next(),不然不会进入钩子。

// main.js
import Vue from 'vue'
import VueRouter from 'vue-router'

import App from './App.vue'

import createRouter from './router/router'

Vue.config.productionTip = false

Vue.use(VueRouter)
const router = createRouter()

// 全局导航守卫
router.beforeEach((to, from, next) => {
  console.log('main beforeEach invoked')
  if (to.fullPath !== '/login') { // 路由匹配到才回去执行 next,如果不匹配,只打印 beforeEach invoked,而不会继续打印beforeResolve invoked 和 afterEach invoked
    next('/login')
  }else {
    next () // 执行 next 后路由才会被跳转
  }
})
router.beforeResolve((to, from, next) => {
  console.log('main beforeResolve invoked')
  next()
})
router.afterEach((to, from) => { // 每次导航跳转结束后被触发,因为已经跳转,所以不再需要 next
  console.log('main afterEach invoked')
})

new Vue({
  router,
  render: h => h(App),
}).$mount('#app')

页面触发顺序(每次路由变化都会被触发):

4-2-1-1.png

4.2.2 路由导航守卫

// routes.js
export default [
  //...
  {
    path: '/login/:id',
    props: {
      id: '456',
      sex: 'man'
    },
    components: {
        default: Login,
        myRouteView: Home
    },
    name: Login,
    meta: {
      title: 'This is Login Page',
      description: 'This is Login Page description'
    },
    children: [
      {
        path: 'loginChild',
        component: () => import('../view/loginChild')
      }
    ],
    // 在路由配置时增加钩子
    // 进入这个路由前调用这个钩子,调用顺序在 beforeEach 和 beforeResolve 之间
    beforeEnter (to, from, next) {
      console.log('route beforeEnter')
      next()
    }
  },
  //...
]

页面触发顺序:

4-2-2-1.png

4.2.3 组件导航守卫

beforeRouteEnter 时,组件尚未被创建(未实例化),故还无法取到 this,无法调用 this 上任何内容,也无法给 this 赋值。这时可使用组件对象 vm (即组件创建后 this 的对象)。

beforeRouteLeave 可用于让用户确认是否离开次路由。

<!-- beforeRouteLeave -->
<template>
  <div>
    <div>Login页内容</div>
    <router-view />
  </div>
</template>

<script>
  export default {
    props: ['id', 'sex'],
    mounted () {
      console.log(this.id, this.sex)
    },
    beforeRouteEnter (to, from, next) {
      console.log("component beforeRouteEnter")
      next(vm => {
        console.log(this) // 打印为 undefined
        console.log(vm.id)
      })
    },
    beforeRouteUpdate (to, from, next) {
      console.log("component beforeRouteUpdate")
      next()
    },
    beforeRouteLeave (to, from, next) {
      console.log("component beforeRouteLeave")
      next()
    }
  }
</script>

进入页面时触发顺序(beforeRouteEnter):

4-2-3-1.png

更新页面时触发顺序(beforeRouteUpdate,例如 login/123 切换至 login/456Login 组件不会被销毁后重建,而是内容更新):

4-2-3-2.png

切换页面时触发顺序(beforeRouteLeave):

4-2-3-3.png

提示:例如 login/123 切换至 login/456 是,由于 Login 组件复用,不会再次去调用 mounted,此时可使用 beforeRouteUpdate

4.3 异步组件

路由在非常多的情况下,如果通过 webpack 一次性打包所有代码,会导致 js 文件庞大,初次加载耗时,且访问某一页面时也加载了其他页面的 js 代码,造成资源浪费。如果对于某一路由,只加载对应页面代码及核心代码,其他页面代码待访问时再加载,可使用异步组件加载,提高首屏加载速度。

// routes.js
export default [
  //...
  {
    path: '/login/:id',
    props: {
      id: '456',
      sex: 'man'
    },
    components: {
        default: Login,
        myRouteView: Home
    },
    name: Login,
    meta: {
      title: 'This is Login Page',
      description: 'This is Login Page description'
    },
    children: [
      {
        path: 'loginChild',
        component: () => import('../view/loginChild') // 异步组件加载,routers.js 顶部不必再引入 loginChild 组件
      }
    ],
    beforeEnter (to, from, next) {
      console.log('route beforeEnter')
      next()
    }
  },
  //...
]
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,108评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,699评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,812评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,236评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,583评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,739评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,957评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,704评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,447评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,643评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,133评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,486评论 3 256
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,151评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,889评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,782评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,681评论 2 272

推荐阅读更多精彩内容