写篇文章之必须马上精通vue——(20)全家桶vue-router

370 阅读4分钟

Vue是渐进式框架,有个全家桶。vue-router顾名思义就是负责路由设置。

vue-router

路由分为两种:

  • 后端路由,请求路由地址不同,后端响应不同的网页数据。是网页本身全部改变。

  • 前端路由,请求路由地址不同,前端展示不同的组件组合。网页只进行局部的改变。

基本使用

路由提供了router-link和router-view两个标签。 router-link 负责路由触发,<router-link to="/About">Home</router-link>等效于<a to="/#About">Home</a>router-view 负责展示对应路由下的组件。router-view和router-link配合实现前端路由功能。

<template>
  <div id="app">
    <div id="nav">
      <router-link to="/">Home</router-link> |
      <router-link to="/About">About</router-link>
    </div>
    <router-view/>
  </div>
</template>
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import About from ......
let routes = [  {
            path: '/',
            name: 'Home',
            component: Home
          },
          {
            path: '/About',
            name: 'About',
            component: About
          }
]

let router = new VueRouter({
    routes
})
export default router
let app = new Vue({
    el: '#app',
    router: router,
    ......
})
//或则
import Vue from 'vue'
import App from './App.vue'
import router from './router'

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

因为组件动态调用在router业务代码中,所以组件只需要在router处引入就行,根组件再引入router即可。

路由重定向

重定向与3xx状态码有关,不过这里前端路由重定向仍然只是操作前端组件。

  • 最简单的写法
{
    path: '/ab',
    name: 'About',
    redirect: '/about',//重定向到当前地址
},
{
    path: '/About',//重定向过来
    name: 'About',
    component: About
}

这样<router-link to="/About"><router-link to="/ab">都会指向路由path: '/About'

几种路由模式

三种 hash、history、abstract模式。

从面试的角度我们从应用场景进行区分。

  • hash模式:兼容所有浏览器,特点是在url地址后添加/#/http://www.juejinjin.com/#/home#/home是hash值。hash值得变化不会使浏览器发送请求。

  • history模式:需要H5标准的支持,因为基层依靠History API实现。路由地址中没有#

  • abstract(抽象)模式:兼容性最强,只需要JavaScript运行环境,如果没有浏览器运行环境就会自动选择该模式。

兼容性:abstract > hash > history

我们通过向mode属性赋值来选择不同的路由模式。

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

两种传参

三种传参:query格式参数、params格式传参。

首先我们可以打印我们的路由属性对象:

console.log(this.$route)//this指向的组件的路由对象

image.png

我们可以看到query和params属性以及path。。

query格式参数

query格式,get请求就是使用该方式携带数据。具体写法如下:

//使用?作为开头连接url地址,以&作为每个变量的分隔符。
url?xxx=yyy&xxk=yyk.....

我们可以直接在运行的vue项目中输入我们写好的路由后添加query格式后缀。或则router-link标签属性to中给路由地址添加后缀。

<router-link to="/new?name=1312">New</router-link>

image.png

  • 主要还是获取,我们通过当前路由对象this.route进行获取,对应属性就是query
      console.log(this.$route,this.$route.query)

params格式传参

params与node后台中的传参写法一致,需要根据路由的name值进行路由匹配:

      this.$router.push({
        name: "Abouts",
        params: {
          name: "word",
          age: "11",
        },
      });

关于接收路由path写法:

  {
    path: '/Abouts/:name/:age',
    name: 'Abouts',
    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
  },

你会发现path: '/Abouts/:name/:age'path: '/Abouts'效果都是一样,我们params的传参都会成功,通过this.$route.params

原则上: params是路由的一部分,必须要在路由后面添加参数名。query是拼接在url后面的参数,没有也没关系。

  • 如果路由后添加了params参数格式,而实际传参不匹配就会报错,或则警告提示:
[vue-router] missing param for named route "Abouts": Expected "name" to be defined
  • 其次我们应该少用params传参,因为params要求使用name进行路由匹配,一方面路由可能没有写name属性,另一方面name容易在开发中出现重名甚至嵌套的路由中出现重名bug后不容易发现。所以路由传参优先query方式。

方法动态导航

动态导航到新路由可以通过router对象上一系列方法:push replace go back forward

我们前面params中使用了push方法,初了push,根路由上每个方法都有便捷的功能:

//我们使用push方法完成一个$router路由对象内的路由跳转。
this.$router.push({path:"/xxxx",query:{xxx}});
this.$router.push({name:"xxxx",query:{xxx},params:{xxx}});

this.$router.replace()

$route 和 $router

$route 这个属性是只读的,里面的属性是 immutable (不可变) 的,不过可以 watch (监测变化) 它。

console.log(this.$route)//this指向的组件的路由对象
console.log(this.$router)//全局路由的实例

image.png

image.png

两者差别体现于全局和局部路由,使用时注意容易用混导致bug。

路由守卫

守卫可以理解为生命周期与路由控制的结合。我们通常通过路由守卫完成登录状态检测等路由验证操作。

前置守卫

可以是理解是生命周期是因为,守卫函数执行在路由跳转离开的前后:

//src\router\index.js
router.beforeEach((to, from, next) => {
  console.log(to,from);
  next();
})
//默认时等效于下面。
router.beforeEach(() => {
  next();
})
  • 全局前置守卫 beforeEach

beforeEach在跳转到新路由之前触发。参数to合from分别是新的路由信息与原来的路由信息,函数内部必须要通过next完成跳转路由的操作,如果不写就会报错。

image.png

  • 关于next()默认是跳转到to所指的新路由,可以手动设置重定向到其他路由。

确保要调用 next 方法,否则钩子就不会被 resolved

//关于登录状态的检测
router.beforeEach((to, from, next) => {
  let isD = sessionStorage.getItem('isD')
  console.log(to, from, isD);
  if(isD=="true"){
    if(to.path!='/user'){
      next('/user')
    }else{
      next()
    }
  }else{
    next()
  }
})

我们发现next重定向路由后,会再次执行beforeEach函数,并将to路由信息修改成'/user'路由。由此我们容易触发死循环:比如from.path!='/user'从非user页面到其他页面就会触发死循环(递归地狱),不断执行beforeEach函数

触发bug死循环后,最好检查路由的判断逻辑。

next补充

  • next(false) : 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。

  • next(error) : 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError()注册过的回调。

全局后置钩子

官方的定义是在路由跳转后执行。

router.afterEach((to, from) => {
  console.log(to,from)
  debugger;
})

通过上述代码,我们可以看到:

image.png

于是我们可以进一步总结:afterEach在完成路由跳转后执行,此时视图层还未更新,只有地址栏完成了变化。

与beforeEach的区别除了触发时间意外,还有:不会接受 next 函数也不会改变导航本身。

路由独享的守卫