Vue的动态路由及导航守卫

动态路由

在正常的项目中,除了上一章中讲到的标准路由输出,更多情况下我们会通过动态路由加JavaScript代码的形式来控制页面的跳转。

通过JavaScript代码控制的方法在上一章最后已有演示,下来我们还是已上一节的案例为演示进行展示。

老规矩,翠花上代码:

  1. 将router/index.js中引入动态路由的组件,在path后如下所示:id
 {
    path: "/about/:id",
    name: "About",
    // 路由的懒加载写法,该组件会被延迟加载,推荐这样写
    component: () =>
      import(/* webpackChunkName: "about" */ "../views/About.vue")
  }

 

  1. 将App.vue中代码修改如下
<template>
  <div id="app">
    <div id="nav">
      <router-link to="/">Home</router-link> |
      <router-link to="'/about' + id">About</router-link>
     
    </div>
    <router-view/>
  </div>
</template>

<script>
    export default {
      data:function(){
        return {
          id: 123
        }
      },
 </script>

这样之后我们可以看到路由中的id会自动匹配到我们在组建data中传入的id值,这就是动态路由的基本使用,如果想动态获取路由中id值可以通过两种方式:

  1. 通过$route.params.id直接获取
  2. 用一个计算属性获取!
<script>
    export default {
      data:function(){
        return {
          id: 123
        },
       computed:{
       	Id(){
          // $route谁处于活跃状态就获取谁
          return this.$route.params.id
        }
       }
      },
 </script>

动态路由通过js方式传参

先说一个这种方式传参的使用场景,一般我们在网站中进行搜索,筛选,排序等操作的时候一般会使用get请求,那么get请求的url要实现这种功能一般会向url中传递参数,形式如下所示:

https://www.baidu.com/s?wd=vue

问号后边的wd=vue就是url种传的参数!

  • 普及个知识点,url的构成:

一个url可以由七个部分构成:协议部分(http/https),域名部分(www.baidu.com), 端口部分(:8000),虚拟目录部分(/news/),文件部分(从域名后的最后一个“/”开始到“?”为止),锚部分(从“#”开始到最后),参数部分(从“?”开始到“#”为止)。

具体大家可自行了解!

  1. 在vue中构造这种get请求一般是通过,path搭配query (类似get),可以通过$route.query获取传递的参数!

老规矩,翠花上代码:

<!--App.vue-->

<h1>代码跳转</h1>
<button @click="ProfileClick">Profile</button>

<script>
export default {
  methods: {
    ProfileClick(){
      this.$router.push({
        path: '/profile',
        query: {
          name: 'vue',
          age: 18,
          height: 10
        }
      })
    }
  },
}
</script>

点击ProfileClick事件会跳转至如http://www.xxx.com/profile?name=vue&age=18&height=10形式的地址!

  1. 在vue中构造这种post请求一般是通过,name搭配params (类似post)

使用场景一般是我们向post接口传送数据,就可以使用这种方式向接口传递参数!

老规矩,翠花上代码:

<!--App.vue-->

<h1>代码跳转</h1>
<button @click="UserClick">Profile</button>

<script>
export default {
  methods: {
    ProfileClick(){
      this.$router.push({
        name: 'user',
        query: {
          id: 12,
          name: 'vue',
          desc: '学习vue'
        }
      })
    }
  },
}
</script>

通过这种方式可以向post请求接口推送数据,其传递的参数可以通过$route.params获取!

嵌套路由

如果一个大的路由下边有小的分支路由,与创建路由的原则相一致,一个路由对应一个组件,子路由也得一一对应相关组件,之后再把注册的路由通过<router-link>引入到父路由的组件中。

老规矩,翠花上代码!

// router/index.js
// 引入子组件,自己提前在views文件夹下创建页面组件!
const Home = () => import('../views/Home.vue')
const HomeNews = () => import('../views/HomeNews')
const HomeMessage = () => import('../views/HomeMessage')

const routes = [
 {
    path: '/',
    name: 'home',
    component: Home,
    // 子组件
    children: [
    // 跳转链接
      {
        path: '/',
        redirect: '/home/news'
      },
      {
      // path路径要与引用到组件的一致
        path: '/home/news',
        component: HomeNews
      },
      {
        path: '/home/message',
        component: HomeMessage
      }
    ]
  },
]

将子路由引入到父路由的组件中。

<router-link to="/home/news">news</router-link> | 
<router-link to="/home/message">message</router-link>
</router-view>

导航守卫

导航守卫的意思是,监听每一个路由的跳转过程,,然后提供了一些钩子让你有机会在路由跳转的过程中植入相关信息,导航守卫分为三个部分即全局导航守卫、路由导航守卫和组件守卫。

全局导航守卫

全局导航守卫分为以下三类,建议大家先去看下vue官网关于这块,有个基础的了解!

1. 全局前置守卫:

  • router.beforeEach,在路由跳转时回调!
router.beforeEach((to, from, next) => {
	// 如果用户未能验证身份,则 `next` 会被调用到登录页
  if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
  else next()
})

2. 全局解析守卫

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

3. 全局后置钩子

  • router.afterEach 跳转完回调!

路由独享守卫

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

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

这些守卫与全局前置守卫的方法参数是一样的。

组件内守卫

最后,你可以在路由组件内直接定义以下路由导航守卫:

  • beforeRouteEnter
beforeRouteEnter (to, from, next) {},

 

在渲染该组件的对应路由被 confirm 前调用,不!能!获取组件实例 this,因为当守卫执行前,组件实例还没被创建。不过,你可以通过传一个回调给 next来访问组件实例。在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数。

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

 

对于 beforeRouteUpdate 和 beforeRouteLeave 来说,this 已经可用了,所以不支持传递回调,因为没有必要了。

  • beforeRouteUpdate (2.2 新增)

在当前路由改变,但是该组件被复用时调用,举例来说,对于一个带有动态参数的路径,/foo/:id,在 /foo/1/foo/2 之间跳转的时候,由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。可以访问组件实例 this!

beforeRouteUpdate (to, from, next) {
  // just use `this`
  this.name = to.params.name
  next()
}

 

  • beforeRouteLeave

导航离开该组件的对应路由时调用,可以访问组件实例 this,这个离开守卫通常用来禁止用户在还未保存修改前突然离开。该导航可以通过 next(false) 来取消。

beforeRouteLeave (to, from, next) {
  const answer = window.confirm('Do you really want to leave? you have unsaved changes!')
  if (answer) {
    next()
  } else {
    next(false)
  }
}

在router/index.js中修改并添加相关信息如下:


// router/index.js

// 01. 在导航路由中添加 meta对象 元数据
{
    path: '/home/message',
    name: 'message',
    component: HomeMessage,
    meta: {
        title: '消息'
    }
}

// 02. 添加如下方法
// 全局导航守卫,router是我们最开始new 出来的一个对象

// 全局导航守卫【前置钩子,跳转时回调】
router.beforeEach((to, from, next) => {
  // 从from跳转到to
  document.title = to.matched[0].meta.title
  console.log('+++++++++')
  next()
  
})

// 后置钩子,跳转完回调
router.afterEach((to, from) => {
  // to and from are both route objects.
  console.log('----------')
})

完整的导航解析流程

  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 的回调函数,创建好的组件实例会作为回调函数的参数传入。