Vue中路由相关:路由原理(router-link)、嵌套路由、编程导航、路由守卫

139 阅读5分钟

1. 路由原理及SPA

1.1 路由原理
  • 传统开发方式 url改变后 立刻发起请求,响应整个页面,渲染整个页面;
  • SPA:锚点值改变后,不会发起请求,而是发起ajax请求,局部改变页面数据,页面不跳转 用户体验更好;
1.2 SPA(single page Application)
  • 一个页面,局部内容根据url不同进行改变;
  • ajax异步请求(实现无感的请求数据);
  • 监控锚点值的改变 => 变化不同内容;
1.3 router-link(动态路由组件)
  • 在支持路由的应用中实现导航的功能;
  • 默认渲染成带有正确链接的a标签;
  • 在 HTML5 history 模式下,router-link 会守卫点击事件,让浏览器不再重新加载页面;
  • 在 HTML5 history 模式下,router-link 会守卫点击事件,让浏览器不再重新加载页面;
1.3.1 router-link组件的一些属性
  1. to:帮助我们生成a标签的href,点击组件,会将to属性的值传递给router.push();to 属性的值可以是一个字符串或者是描述目标url的对象;举例:

<router-link to="/xxx/x">点我</router-link>

  • 以上是to属性值为字符串的举例,此时锚点值代码维护不方便,如果需要改变锚点值名称,则需要改变 [使用次数 + 1(配置规则)] 个地方的代码;

<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>

  • 以上是to属性值为对象的举例,实现了命名路由,通过名称找路由对象,获取其path,生成自己的href,大大降低维护成本,锚点值改变只用在main.js中改变path属性即可;
  1. append:属性值为布尔值,决定是否为相对路径,当值为true时,跳转到新的相对路径(/b)时,是在当前路径(/a)作为基路径的情况下(/a/b)实现的,举例:

<router-link to="/xxx/x" append>点我</router-link>

  1. tag:属性值类型为字符串,定义router-link动态路由组件最终渲染的组件类型,默认渲染为a组件,举例: <router-link to="/foo" tag="li">foo</router-link>

以上代码会渲染成可点击跳转的li组件

  1. active-class:属性值为字符串类型,默认值是router-link-active",表示组件跳转到的链接激活时的CSS属性名;
  2. exact:属性值是布尔类型,链接跳转默认是包含匹配,比如所有包含<router-link to="/">的链接都会激活到'/'地址的跳转,添加exact属性后就可以实现精准匹配,只有完全一致的链接才会跳转;
  3. exact:属性值为字符串或者字符串数组,定义触发链接跳转的事件类型,默认值是'click';
1.3.2 router-link组件的常用方法
  1. 查询字符串
  • 配置:to="{name:'detail',query:{id:hero.id} }"
  • 规则 {name:'detail',path:'/detail',component:Detail}
  • 获取 this.$route.query.id
  • 生成 <a href="/detail?id=1">
  1. path方式
  • 配置 :to="{name:'detail',params:{id:hero.id} }"
  • 规则 { name:'detail',path:'/detail/:id'}
  • 获取 this.$route.params.id
  • 生成 <a href="/detail/1">
  • 注意:path方式需要在路由规则中声明位置;
1.3.3 重定向
  1. 方式一:字符串路径path:{ path: '/a', redirect: '/b' }
  2. 方式二:name:{ path: '/a', redirect: {name: 'b'} }
  3. 方式三:动态返回重定向目标:
{ path: '/a', redirect: to => {
  // 方法接收 目标路由 作为参数;return 重定向的 字符串路径/路径对象
}}
1.3.4 vue-router使用步骤
  1. 引入import VueRouter from 'vue-router'
  2. 安装插件
  3. 创建路由实例
  4. 配置路由规则
  5. 将路由对象关联vue
  6. 留坑

2. 嵌套路由

2.1 router-view组件
  • name属性值为字符串类型,默认值是"default",当用户设置了name属性值,则会渲染对应的路由配置中 components 下的相应组件;
2.2 嵌套路由原理
  1. 代码思想
  • 第一层router-view中,包含一个router-view,即router-view的细分;
  • 此时每一个坑挖好了,都要对应单独的组件;
  1. 使用须知
  • 代码形式为router-view包含router-view;
  • 路由中包含children属性的子路由;
  1. 举例

导航组件准备:

<template>
  <div id="app">
    <nav>
      <router-link :to="{ name: 'dashboard' }">嵌套路由:父</router-link> |
      <router-link :to="{ name: 'movie' }">嵌套路由:电影</router-link> |
      <router-link :to="{ name: 'sing' }">嵌套路由:歌曲</router-link> |
    </nav>
  </div>
</template>

以下是路由配置:

router.addRoute({ // 懒加载:当访问的时候组件才被加载
  path: '/dashboard',
  name: 'dashboard',
  component: () => import(/* webpackChunkName: "about" */ '../views/Dashboard.vue'),
  children: [
    {
      name: 'movie',
      path: 'movie',
      meta: { title: '成人电影' },
      component: () => import(/* webpackChunkName: "about" */ '../views/Movie.vue'),
    },
    {
      name: 'sing',
      path: 'sing',
      component: () => import(/* webpackChunkName: "about" */ '../views/Sing.vue'),
    }
  ]
})

3.路由守卫

  • 它其实就是一个路由改变的事件回调函数;
  • 主要用来通过跳转或取消的方式守卫导航;
3.1 全局路由守卫
  • 前置router.beforeEach((to, from,next) => {})
  • 后置router.afterEach((to, from) => {})
  • next(false); 取消用户导航行为;
  • next();// 放行到你想to的路由;
router.beforeEach((to, from, next) => {
  if (to.meta.title) {
    document.title = to.meta.title;
  }
  // 路由鉴权 + 动态生成路由的逻辑, 如果没有调用next() 则会出现白屏
  // 重定向
  if (!window.closeDoor) {
    window.closeDoor = true;
    next({
      name: 'sing', query: { id: 123 }
    })
  } else {
    next();
  }
});
3.2 路由独享的守卫(路由独享的守卫)
  • 与全局前置守卫的方法参数是一样的;
const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) =>{
        // ...
      }
    }
  ]
})
3.3 组件内的守卫
  • 包括beforeRouteEnter、beforeRouteUpdate (2.2 新增)、beforeRouteLeave;
  • 在渲染该组件的对应路由被 confirm 前调用;
  • 不!能!获取组件实例 this, 因为当守卫执行前,组件实例还没被创建;
  • 但是,可以通过 vm 访问组件实例-> 未来的组件this:
next(vm => {
  // 通过 `vm` 访问组件实例-> 未来的组件this
    vm.msg = '数据在此';
})
3.3.1 组件内的守卫的一些举例
  • beforeRouteUpdate的触发条件(动态路由参数变化时);
  • beforeRouteLeave:导航离开该组件的对应路由时调用;
<template>
  <router-link to="/xxx/1">1</router-link>
  <router-link to="/xxx/2">2</router-link>
</template>

<script>
  const Foo = {
    template: `...`,
    beforeRouteEnter (to, from, next) 
        next(vm => {
          // 通过 `vm` 访问组件实例-> 未来的组件this
            vm.msg = '数据在此';
        })
    },
    beforeRouteUpdate (to, from, next) {
      // 可以访问组件实例 `this`
    },
    beforeRouteLeave (to, from, next) {
      // 可以访问组件实例 `this`
    }
  }
</script>
3.3.2 守卫meta属性的应用
  • 路由meta元数据 -> meta是对于路由规则是否需要验证权限的配置;
  • 路由对象中 和name属性同级 { meta:{ isChecked:true } }
  • 路由钩子 -> 权限控制的函数执行时期;
  • 每次路由匹配后, 渲染组件到router-view之前;
router.beforeEach(function(to,from,next) {
  // 判断to或from的fullPath即可
} )

4. 编程导航

  1. 跳到指定的锚点,并显示页面 this.

$router.push/replace({ name:'xxx',query:{id:1},params:{name:'abc'} });

  1. 配置规则 {name:'xxx',path:'/xxx/:name'}
  2. 根据历史记录.前进或后退this.$router.go(-1|1)
  3. 1代表进一步,-1是退一步;

5. 过渡效果及缓存(transition内置组件)

  • 我们需要在路由改变时变化页面,ok!同时我们希望加上一些淡入淡出等效果,就可以用上transition内置组件;
  • 另外,考虑到缓存问题,就加上keep-alive组件结合使用;
<transition>
  <keep-alive>
    <router-view></router-view>
  </keep-alive>
</transition>