0
点赞
收藏
分享

微信扫一扫

vue-router技术详解

1.Link标签:Link标签本质上也是a标签,不过它禁止了a标签的默认事件,通过history的相关事件来进行跳转,route内部也可以通过捕获这个事件来进行相关的逻辑处理。

2.路由导航:路由的钩子函数有三类,全局守卫、路由守卫、组件内守卫。全局守卫在每次导航时都会触发,一般会新起一个文件,然后引入main.js中,涉及的钩子函数有beforeEach、afterEach、beforeReslove等。路由守卫则是在进入路由时触发,一般在定义路由的时候使用,比如在路由路径下添加一个的属性beforeEnter。组件内守卫则是在进入或离开组件前调用。这三种守卫一般都包含三个参数to、from、next,to和from不多说了,next参数可以不添加,但是一旦添加,则必须调用一次,否则路由跳转就会停止。

3.组件递归:首先要为组件命名name,这样可以在组件内继续调用该组件,然后可以用v-for去循环,这边key最好使用唯一ID,免得增加不必要的消耗,且需要判断传入数据是否为空,告知v-for什么时候停止渲染,数据的话仍旧使用树形结构的数据即可。组件名称name同时也可以搭配keep-alive使用,它能使被包含的组件保留状态,避免重新渲染,这里相关的属性有include、exclude以及activated和deactivated两个钩子函数。

4.mode模式:路由提供hash以及history两种方式,默认是hash,它们在url上的区别是hash模式会有一个#的锚点来区分,而history没有。在原理上的区别是hash模式利用了window可以监听onhashchange事件来实现的,而history模式是通过调用window.history对象上的一系列方法来实现,比如pushState和replaceState方法。在与服务器交互上的区别是hash模式只会将#锚点前的url发送给服务器,而history模式则会将完整的url发送给服务器,因此在生产环境中,history模式需要服务器设置代理转发,对于不识别的路径,统一处理重定向到项目首页,否则在刷新的时候会出现404的情况。

知识点

1.路由

路由跳转

  1. router-link:实际为a标签,不过它禁止了a标签的默认事件,通过history的相关事件来进行跳转。

<router-link :to="keyframes">
  <div>zxp</div>
</router-link>
//keyframes为router中的path

  1. replace

this.$router.replace({path:'/user'})
//该方式,history栈中不会有记录

  1. go

this.$router.go(n)
//向前或者向后跳转n个页面,n可为正整数(向后)或负整数(向前)

  1. 带参跳转
  • 动态路由

getRouter(id){
  this.$router.push({
    path:`test/${id}`
  })
}
//path后的引号得用模板字符串,而不是单引号,因为有变量

{
  path:'/user/:userId',
  component:User
}

//获取的路由如:'/user/123456'
//this.$route.userId   123456

  • param传递

this.$router.push({
  name:'test',
  params:{
    id:id
  }
})
//获取方式:this.$route.params.id
//该方式类似get请求,浏览器url在路径后面会显示id值,去掉id页面加载会异常

  • query传递

this.$router.push({
  name:'test',
  query:{
    id:id
  }
})
//获取方式:this.$route.query.id

//该方式类似post请求,浏览器url不显示id值

路由懒加载

路由懒加载也叫作延迟加载,使用懒加载可以减少我们第一次打开项目首页的时间,不至于页面出现长时间的白屏,从而优化用户的体验。

export default new Router({
  routes: [
    {
      path: '/test',
      name: 'testRouter',
      component: () => import('../page/test.vue')
    }
  ]
})

嵌套路由、重定向

{
    path: '/parent',
    component: () => import('../page/parent.vue'), // 父路由的公共部分
    redirect:'/parent/common'
    children: [
        {
          path: 'common', // 进入父路由时,重定向跳转
          name: 'common',
          component:  () => import('../page/common.vue')
        },
        {
          path: 'child',// 其他子路由,这里注意,不要加 '/',否则会匹配根路由
          name: 'child',
          component:  () => import('../page/child.vue')
        }
    ]
}

2.导航守卫

导航守卫主要用来通过跳转或取消的方式守卫导航。有多种机会植入路由导航过程中:全局的, 单个路由独享的, 或者组件级的。 参考链接:https://juejin.cn/post/7139932176141893669

  • 全局导航守卫

全局路由守卫有三种:

  1. 全局前置守卫:router.beforeEach,主要作用就是用于在进入路由前做一些逻辑操作,如登录验证;

// 缓存登录状
sessionStorage.setItem('username',this.ruleForm.username)

// main.js
router.beforeEach((to,from,next) => {  //路由跳转的前置钩子
  if(!sessionStorage.getItem('username') && to.name !== 'login') {
    next({name: 'login'}) // 路由名称
  }else{
    next()
  }
})

  1. 全局解析守卫:router.beforeResolve
    官方解释其与beforeEach的区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用,即在beforeEach和组件内beforeRouteEnter之后,afterEach之前调用。

// main.js
router.beforeResolve((to,from,next) => {
  console.log(to,from);
  next()
})

PS:以上两个钩子函数执行时,还在当前页面,未跳转到跳转的页面

  1. 全局后置守卫:router.afterEach
    和beforeEach相反,它是在路由跳转完成后触发,参数包括to,from没有了next,它发生在beforeEach和beforeResolve之后,beforeRouteEnter(组件路由守卫)之前,它是在路由跳转之后触发的,可以获取到路由跳转之后的dom结构。

router.afterEach((to,from) => {
  console.log(to,from);
  if(!sessionStorage.getItem('username') && to.name !== 'login') {
    router.push('/login')
  }
})

  • 独享守卫
    beforeEnter(独享守卫)通常是某一个或几个页面独有的,所以我们通常会将路由独享守卫写在/src/router/index.js里,目的是有些需要要求进入一些页面有要求,比如要求已登录的状态等,如购物车。

// router/index.js
{
   path: '/detail',
   name: 'detail',
   component: () => import('@/views/Detail.vue'),
   beforeEnter: (to,from,next) => {
     if(!sessionStorage.getItem('username')) {
       alert('请先登录')
       // next({name: 'login'})
       router.push('/login')
     } else {
       next()
     }
   }
}

  • 组件路由守卫
    组件路由守卫是组件内的钩子函数,类似于组件内的生命周期,钩子函数执行的顺序包括beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave三个,执行位置如下:

<template>
  ...
</template>
export default{
  data(){
    //...
  },
  beforeRouteEnter (to, from, next) {
    // 在渲染该组件的对应路由被 confirm 前调用
    // 不!能!获取组件实例 `this`
    // 因为当守卫执行前,组件实例还没被创建
  },
  beforeRouteUpdate (to, from, next) {
    // 在当前路由改变,但是该组件被复用时调用
    // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
    // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
    // 可以访问组件实例 `this`
  },
  beforeRouteLeave (to, from, next) {
    // 导航离开该组件的对应路由时调用
    // 可以访问组件实例 `this`
  }
}
<style>
  ...
</style>

  1. 但凡涉及到有next参数的钩子,必须调用next()才能继续往下执行下一个钩子,否则路由跳转等会停止。
  2. 如果要中断当前的导航要调用next(false)。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到from路由对应的地址。(主要用于登录验证不通过的处理)
  3. next('/')或者next({ path: '/' }): 跳转到一个不同的地址,可传递的参数与router.push中选项一致。
  4. 在beforeRouteEnter钩子中next((item)=>{})内接收的回调函数参数为当前组件的实例item,这个回调函数在生命周期mounted之后调用,也就是,他是所有导航守卫和生命周期函数最后执行的那个钩子。

3.keep-alive

keep-alive可以实现组件缓存,当组件切换时不会对当前组件进行卸载。 它的原理是在created函数调用时将需要缓存的vnode节点保存在this.cache当中,如果符合条件则从cache取出vnode实例进行渲染。

主要是有以下三个属性

  • include:需要缓存的数据,支持字符串,数组,正则
  • exclude:不需要缓存的数据,支持字符串,数组,正则
  • max:缓存的最大组件数量,支持数字和字符串,如果超过了这个个数的话,在下一个新实例创建之前,就会将以缓存组件中最久没有被访问到的实例销毁掉。
    基础使用方式:

//router.js
import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue'
Vue.use(Router)
export default new Router({
  routes: [
    {
      path: '/',
      name: 'home',
      component: Home,
      // 需要被缓存
      meta: {
        keepAlive: true    //这里的keepAlive可以自定义,比如noCache,那么在使用时也需要同步,如下Layout.vue
      }
    },
    {
      path: '/about',
      name: 'about',
      component: () => import('./views/About.vue')
    },
  ]
})

//布局组件,如Layout.vue
<template>
  <div id="app">
  //keep-alive包裹的子组件只能有一个
    <keep-alive>
      <router-view v-if="$route.meta.keepAlive"></router-view>
    </keep-alive>
    <router-view v-if="!$route.meta.keepAlive"></router-view>
  </div>
</template>

  • 组件一旦被keep-alive缓存,那么就不会再执行created、mounted等钩子函数, 因此提供了activated和deactivated钩子函数,执行顺序:第一次进入-->created--> mounted--> activated -->退出-->deactivated -->第二次进入-->activated
    注意事项:
  1. keep-alive先匹配被包含组件的name字段,如果name不可用,则匹配当前组件component配置中的注册名称
  2. keep-alive不会在函数式组件中正常工作,因为它们没有缓存实例。
  3. 当匹配条件同时在include与exclude存在时,以exclude优先级最高。
  4. 包含在keep-alive中,但符合exclude,不会调用activated和deactivated

4.路由模式

前端路由有两种模式:hash模式和history模式,下面具体来看看其特点:

  • history
    history允许开发者直接更改前端路由,即更新浏览器URL地址而不重新发起请求,并且提供了丰富的函数供开发者调用,比如

history.replaceState({}, null, '/b') // 替换路由
history.pushState({}, null, '/a') // 路由压栈
history.back() // 返回
history.forward() // 前进
history.go(-1) // 后退1次

  • hash
    hash模式是一种把前端路由的路径用#拼接在真实URL后面的模式。当井号#后面的路径发生变化时,浏览器并不会重新发起请求,而是会触发hashchange事件,这种方式浏览器兼容性较好,连 IE8 都支持,但由于有个#比较丑,一般就不采用。
  • 区别
  1. 在url上,hash模式会有一个#的锚点来区分,而history没有。
  2. 在原理上,hash模式利用了window可以监听onhashchange事件来实现的,而history模式是通过调用window.history对象上的一系列方法来实现,比如pushState和replaceState方法。
  3. 在与服务器交互上,hash模式只会将#锚点前的url发送给服务器,而history模式则会将完整的url发送给服务器,因此在生产环境中,history模式需要服务器设置代理转发,对于不识别的路径,统一处理重定向到项目首页,否则在刷新的时候会出现404的情况。
举报

相关推荐

vue-router 常用api详解

Vue-router

Vue-router学习

vue-router路由

搞懂vue-router

0 条评论