vue之路由vue-router

196 阅读4分钟

1. 介绍

Vue.js路由允许我们通过不同的url访问不同的内容

通过Vue.js可以实现多视图的单页Web应用(SPA)

参数或查询的改变并不会触发进入/离开的导航守卫,此时需要通过观察(watch);

$route 对象来应对这些变化,或使用 beforeRouteUpdate 的组件内守卫

2. vue-router使用步骤

2.1 下载安装vue-router

npm install --save vue-router

2.2 创建路由器对象

主模块: router/index.js

// 路由器对象模块

import Vue from 'vue'
// 1.  引入vue-router
import VueRouter from 'vue-router'

// 2.  引入各个路由组件
import Login from '../pages/Login/Login'

// 将一级的路由组件懒加载:设置路由懒加载
// 当使用了组件懒加载以后,MSite是一个返回路由组件的函数,只有在执行此函数时,才会加载路由组件
const MSite = () => import('../pages/MSite/MSite.vue')

// 3.  声明使用VueRouter
Vue.use(VueRouter);

// 4.  配置路由
const routes = [
  {
    path: '/',
    redirect: '/msite',  
    // redirectc 表示如果找不到页面/  就自动跳转到页面 /msite
  },
  {
    path: '/msite',
    // 路由组件函数,会在第一次请求对应的路由路径时,才会执行,因为使用了路由懒加载
    component: MSite,
    // 也可以简写为下面的方式,就不用在上面引入的
    // component:()=>import('../pages/MSite/MSite.vue')  
    name:'msitePage'  // 别名:使用的时候可以通过路由别名访问
    meta: {
      // 设置路由对象的参数
      showFooter: true
    }
  },
  {
    path: '/shop',
    component: Shop,
    // 嵌套二级路由
    children: [
      {
        path: '/shop/goods',
        component: ShopGoods
      },
      {
        path: '',
        redirect: '/shop/goods'
      }
    ]
  },
  {
    path: '/login',
    component: Login
  },
]

// 创建 router 实例,然后传 `routes` 配置
export default new VueRouter({
  mode: 'history',
  // 5. 配置所有路由
  routes
})

2.3 注册路由器 (在main.js里面)


import router from './router'
new Vue({
    router
})

2.4 使用路由:router-link标签,用来生成路由组件标签

<!--1.  路径链接跳转-->
<!-- 方式一:直接使用path跳转 -->
<router-link to="/about">Go to XXX</router-link>

<!-- 方式二:使用name对象跳转 -->
<router-link :to="{name:'aboutPage'}">Go to XXX</router-link>


<!-- 2.   router-link默认是解析为a标签,如果想要解析为li标签,设置tag属性-->
<router-link tag="li" to="/about">Go to XXX</router-link>

<!-- 3.  设置 链接激活时使用的 CSS 类名 active-class -->
<router-link to = "/about" active-class = "activeClass">XXX</router-link>


<!-- 4.   router-view 用来显示当前路由组件的页面  -->
<!-- 路由匹配到的组件将渲染在这里 -->
<router-view></router-view>

3. 编程式路由导航

1) this.$router.push(path): 相当于点击路由链接(可以返回到当前路由界面)

2) this.$router.replace(path): 用新路由替换当前路由(不可以返回到当前路由界面)

3) this.$router.back(): 请求(返回)上一个记录路由

4) this.$router.go(-1): 请求(返回)上一个记录路由

5) this.$router.go(1): 请求下一个记录路由

3.1 请求(返回)上一个记录路由

this.$router.go(-1) == 跳转到上一次的浏览器页面(浏览器的回退按钮)

this.$router.back()

3.2 跳转到指定路由

3.3.1 保存路由记录 push

相当于点击路由链接,可以返回到当前路由界面,浏览器会有一个回退按钮

this.$router.push('/home')

this.$router.push({name:'homePage'})

3.3.2 不保存路由记录 replace

用新路由替换当前路由,不可以返回到当前路由界面

导航后不会留下 history 记录
this.$router.replace(path)

4. 缓存路由组件对象

默认情况下,当切换路由组件对象时,路由组件对象会死亡释放,再次切换回来时是重新创建的

如果可以缓存路由组件对象, 可以提高用户体验

<keep-alive>
  <router-view></router-view>
</keep-alive>

5. 路由参数的传递

案例设置路的由对象如下:

{
    path: '/loginPage',  // path路径 
    name: 'loginLink',   // 路由别名
    component: login 
}

5.1 方法一:编程式导航传递参数

5.1.1 params传参

注意:使用这种方式传递的参数,如果在目标页面刷新是会出错的

  // 设置参数(路由别名跳转):
    this.$router.push({ name: 'loginLink', params: { userId: 123 }})
 	 
  // 接收参数:params
     this.$route.params.userId
     

5.1.2 query传参

  // 设置参数(路由路径跳转):
     this.$router.push({ path: '/loginPage', query: { userId: 123 }});
  	
  // 接收参数:query
     this.$route.query.userId
  	

5.2 方法二:声明式的导航 <router-link> 传参

5.2.1 路由属性携带参数

这种是params传参的方式,目标页面没有 ?

// 1. 配置路由
{
    path: '/loginPage/:userID', //  传递参数userID,采用占位符的方式
    name: 'loginLink',  //  路由别名
    component: login 
}

// 2. 路由router-link设置参数值
   <router-link :to="'/loginPage/'+json.id">{{json.id}}</router-link>

// 3. 组件中获取参数
   this.$route.params.userID
            

5.2.2 router-link设置参数

// 1. 通过  name别名的方式  设置参数:params传参
<router-link :to="{ name: 'loginLink', params: { userId: 1111}}">跳转页面</router-link>
this.$route.params.userId(接收参数)


//  2. 通过  path路径的方式  设置参数:query传参
<router-link :to="{ path: '/stype/details', query: { userId: 1111}}">跳转页面</router-link>
this.$route.query.userId(接收参数)


// 另外一种方式:query传参
<router-link :to="`/stype/details?id=`{{item.id}}">跳转页面</router-link>
//  接收参数
this.$route.query.id

6. 导航守卫

6.1 介绍

vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航

注意: 参数或查询的改变并不会触发进入/离开的导航守卫。你可以通过观察 $route 对象来应对这些变化,或使用 beforeRouteUpdate 的组件内守卫

6.2 全局前置守卫

使用 router.beforeEach 注册一个全局前置守卫:当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于 等待中

确保 next 函数在任何给定的导航守卫中都被严格调用一次。它可以出现多于一次,但是只能在所有的逻辑路径都不重叠的情况下,否则钩子永远都不会被解析或报错

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

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

每个守卫接收的参数说明:

  • to: Route: 即将要进入的目标 路由对象

  • from: Route: 当前导航正要离开的路由

  • next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数

    • next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)
    • next(false): 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址
    • next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向 next 传递任意位置对象,且允许设置诸如 replace: truename: 'home' 之类的选项以及任何用在 router-linkto proprouter.push 中的选项
    • next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调

案例展示:在用户未能验证身份时重定向到 /login

// BAD
router.beforeEach((to, from, next) => {
  if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
  // 如果用户未能验证身份,则 `next` 会被调用两次
  next()
})


// GOOD
router.beforeEach((to, from, next) => {
  if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
  else next()
})


6.3 全局解析守卫

router.beforeResolve 注册一个全局守卫。这和 router.beforeEach 类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用

6.4 全局后置钩子

你也可以注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next 函数也不会改变导航本身

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

6.5 路由独享的守卫

可以在路由配置上直接定义 beforeEnter 守卫

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

6.6 完整的导航解析流程

  1. 导航被触发。
  2. 在失活的组件里调用 beforeRouteLeave 守卫。
  3. 调用全局的 beforeEach 守卫。
  4. 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
  5. 在路由配置里调用 beforeEnter
  6. 解析异步路由组件。
  7. 在被激活的组件里调用 beforeRouteEnter
  8. 调用全局的 beforeResolve 守卫 (2.5+)。
  9. 导航被确认。
  10. 调用全局的 afterEach 钩子。
  11. 触发 DOM 更新。
  12. 调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入