详解Vue-router

本文目录:

  • 1.什么是前端路由
  • 2.vue-router使用步骤
  • 3.什么是单页应用
  • 4.配置路由
  • 5.使用router-link实现跳转
  • 6.嵌套路由
  • 7.命名路由
  • 8.命名视图
  • 9.重定向
  • 10.别名
  • 11.编程式导航
  • 12.动态路由匹配
  • 13.路由组件传参
  • 14.记录滚动位置
  • 15.vue-router中的全局钩子函数
  • 16.vue-router中写到路由记录里的钩子函数
  • 17.写在组件内部的路由钩子函数
  • 18.路由切换的动画效果

1.什么是前端路由

路由这个概念最先是后端出现的,发送不同的请求,后端根据请求的不同返回不同的资源,这个时候的url是和后端交互的,需要在后端去配置路由的跳转,这种开发方式有两个特点,一是整个项目中前端代码和后端代码是柔在一起的,通常都是需要模版引擎来支持,代码杂糅在一起后不方便本地开发调试,一旦后端代码有错误,前端无法进行开发,前端被限制在后端的开发方式中,效率很低,项目通常是后端主导,二是每次切换一个页面都需要去重新请求服务器,即使两个页面有很多相似的地方都需要去重新请求,随着单页应用的发扬光大,MVVM概念兴起,前后端分离以及前端工程化的发展,前端所做的事情越来越多,前端圈快速崛起。这里说的单页应用,通俗的说就是一个页面,是无刷新的,url变化,对应的是组件的切换,前端路由是为了实现这种单页应用而出现的。总结起来就是前端路由就是在前端去控制不同url路径,切换不同的组件,可以认为url和组件是一种映射关系

2.vue-router使用步骤

1.安装模块

npm install vue-router --save

2.引入模块(在router文件夹中的index.js中引入,先import Vue from 'vue',然后)

import VueRouter from 'vue-router'

3.作为Vue的插件

Vue.use(VueRouter)

4.创建路由实例对象

const router = new VueRouter({
  routes: [
    {
      path: '/',
      component: Home
    },
    {
      path: '/questions',
      component: Questions
    },
    {
      path: '/vip',
      component: Vip
    },
    {
      path: '/course',
      component: Course
    }
  ]
})
//对router进行导出
export default router

5.注入Vue选项参数(在main.js中进行引入)

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

6.告诉路由渲染的位置
匹配上的组件会被渲染到router-view这个位置


7.放置跳转标签
路由最开始默认就有一个#号





通过上面的步骤,当我们点击a标签的时候,被匹配到的路由所映射的组件就会被渲染到
注意:上面步骤的讲解主要是为了方便理解,实际应用中的vue项目通常由脚手架工具搭建,搭建的时候勾选上router,项目中就默认配置安装好了vue-router

3.什么是单页应用

百度百科解释,单页Web应用(single page web application,SPA),就是只有一张Web页面的应用,是加载单个HTML 页面并在用户与应用程序交互时动态更新该页面的Web应用程序。

4.配置路由

需求:点击不同的菜单(首页、课程、会员、问答),下方显示不同的文字
首页:App组件代码





路由配置:roiter文件夹中的index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
//下面是引入的四个路由
import Home from '@/components/Home'
import Course from '@/components/Course'
import Question from '@/components/Question'
import Vip from '@/components/Vip'

// 让vue-router作为vue的插件使用
Vue.use(VueRouter)
// 配置路由信息
const router = new VueRouter({
  routes: [
    {
      path: '/',
      component: Home
    },
    {
      path: '/course',
      component: Course
    },
    {
      path: '/vip',
      component: Vip
    },
    {
      path: '/question',
      component: Question
    }
  ]
})
export default router

上面的代码就可以通过点击实现路由的跳转了,但是a标签的路由会在路径前面添加一个"#",显得特别的不优雅,我们可以通过router-link进行优化

5.使用router-link实现跳转

首页:App组件代码

  • 首页
  • 课程
  • 会员
  • 问答
  • router-link的其他配置
    1.可以动态绑定一个变量

  • 首页
  • 课程
  • 会员
  • 问答
  • 2.默认router-link生成的是a标签,可以更改成其他标签, 使用tag来设置

  • 首页
  • 课程
  • 会员
  • 问答
  • 3.设置router-link的激活样式
    第一种方式,在全局配置一个linkActiveClass
    配置路由信息(在router文件夹中的index.js中添加)

    const router = new VueRouter({
      //设置激活样式
      linkActiveClass: 'nav-active',
      routes: [
        {
          path: '/',
          component: Home
        },
        ......
      ]
    })
    

    第一种方式的优先级小于第二种方式
    第二种方式,直接在router-link上增加active-class
    默认情况下是支持的点击事件

  • 首页
  • router-link 的激活样式默认情况下的路由是模糊匹配,例如当前路径是 /article/1 那么也会激活 ,所以当设置 exact-active-class 以后,这个 router-link 只有在当前路由被全包含匹配时才会被激活 exact-active-class 中的 class。

    4.设置渲染组件的公共样式,可以直接在router-view上增加class

    
    

    5.可以更改切换的事件,默认是鼠标点击切换,通过设置event实现

  • 首页
  • 课程
  • 会员
  • 问答
  • 使用router-link进行的路由跳转执行的都是模糊匹配,如果要实现精准匹配,需要在标签中增加上exact属性。

    6.嵌套路由

    当路由越来越多的时候,把全部路由都以平级的关系罗列在一起显得那么的没有逻辑,也让路由变得难以维护,为此,我们可以让存在上下级逻辑关系的路由组合成嵌套路由。
    比如下面这种场景:点击vip路由之后,还可以通过点击不同的区域去展现vip路由下的“一级会员、二级会员、三级会员”路由页面。

    核心代码:需要在vip.vue组件中增加触发路由的 ,并且在这个页面中放置一个,当子路由被匹配到的时候,对应的页面会被渲染到这里。

    
    

    2.在路由文件夹的index.js文件中,需要引入vip路由嵌套下的三个子路由

    import One from '@/components/One'
    import Two from '@/components/Two'
    import Three from '@/components/Three'
    

    同时为vip路由配置children字段

    {
      path: '/vip',
      component: Vip,
      children: [
        {
          path: 'one',  // /vip/one
          component: One
        },
        {
          path: 'two',
          component: Two
        },
        {
          path: 'three',
          component: Three
        }
      ]
    }
    

    7.命名路由

    有时候,通过一个名称来标识一个路由显得更方便一些,特别是在链接一个路由,或者是执行一些跳转的时候,通俗的说,命名路由就是用name属性给路由取一个名字 例如:
    在路由文件夹的index.js文件中,给'/questions'路由增添一个属性name,属性值为这个路由的名字 'wenda'

    {
      path: '/questions',
      name: 'wenda',  //注意这里的name值 wenda
      component: Questions
    },
    ......
    

    在进行路由的使用这个name属性

  • 首页
  • 课程
  • vip
  • 问答
  • 8.命名视图

    有时候想同时 (同级) 展示多个视图,而不是嵌套展示,这个时候可以给视图命名,就可以在一个路由中展示多个视图(组件),并实现把指定的路由组件展现到指定的位置。
    例如: 在home路由中增加侧边栏和主体内容两个组件
    在路由文件夹下的index.js文件中设置路由对应的组件

    //新引进的两个命名视图
    import Sider from '@/components/Sider'
    import HomeContent from '@/components/HomeContent'
    ......
    const router = new VueRouter({
      linkActiveClass: 'nav-active',
      routes: [
        {
          path: '/',
          components: {   //注意这里的components,  default设置的组件 被渲染到  放置的位置
            default: Home,   
            sider: Sider,    //Sider组件被渲染到 放置的位置
            homecontent: HomeContent  //同理
          }
        },
        ...
      ]
    })
    ......
    

    在对应的组件中渲染视图

    
    

    9.重定向

    路由重定向通俗的说就是从一个路由重新定位跳转到另一个路由,例如:访问的 “/a” 重定向到“/b”
    重定向也是通过配置routes选项完成的

    routes: [  
      {
        path: '/course',
        component: Course
      },
      {
        path: '/hello',
        component: Hello,
        redirect: '/course'
      }]
    

    上面代码中,访问 ‘/hello’ 并不会去渲染Hello组件,而是会跳转到路由‘/course’,去渲染course组件
    重定向的目标可以是一个命名路由

    routes: [
      {
        path: '/questions',
        name: 'wenda',
        component: Questions
      },
      {
        path: '/hello',
        component: Hello,
        redirect: {name: 'wenda'}
      }]
    

    上面代码配置后,访问 ‘/hello’就会跳转到命名路由‘wenda’,即‘/questions’,从而去渲染Questions组件
    重定向的目标也可以是一个方法,在方法中可以写一些逻辑代码

    {
      path: '/hello',
      component: Hello,
      redirect: (to) => {
        if (to.hash) {
          return '/questions'
        } else {
          return '/course'
        }
      }
    }
    

    当路径参数对象存在hash值的时候,路由会被跳转到/questions,否则会被跳转到/course

    10.别名

    别名从字面上理解为别的名字,比如有的人有一个中文名,还有一个别的名字英文名。举例: ‘/hello’ 有一个别名 ‘/hi’, 当用户访问‘/hi’的时候,url会保持不变,但是渲染的还是'/hello'对应的组件,说白了就是不管用户访问的是'/hello',还是‘/hi’,找到的都是同一个人(Hello组件)

    routes: [
      {
        path: '/hello',
        component: Hello,
        alias: '/hi'
      }]
    

    11.编程式导航

    首先需要说一下声明式导航,前面我们学过的通过定义导航链接的这种方式叫做声明式导航,特点就是要在template中去写跳转链接,通过生成a标签的形势跳转

     
    • 首页
    • 课程
    • 会员
    • 问答

    编程式导航

    编程式导航通俗的说就是vue-router给我们提供了一堆方法,我们通过在js中编写代码来实现导航切换,这些常用方法包括:back、forward、go、push、replace等
    push
    想要导航到不同的URL,则使用 router.push方法。这个方法会向 history 栈添加一个新的记录

    pushHandle () {
      // this.$router.push('/hello')
      // push内部可以给对象
      this.$router.push({name: 'wenda'})
    }
    

    注意: 在 Vue 实例内部,你可以通过 $router 访问路由实例
    replace
    跟 router.push 很像,唯一的不同就是,它不会向 history 添加新记录,而是跟它的方法名一样 —— 替换掉当前的 history 记录
    back
    back方法可以回到上一步
    forward
    forward方法可以前进一步
    go
    go方法可以一次跳多步
    注意:go里面如果是正数表示前进,如果是负数表示后退
    下面代码代表表示前进2步

    goHandle () {
          this.$router.go(2)
    }
    
    

    12.动态路由匹配

    动态路由意味着不固定,具有某种模式,我们希望通过某种匹配方式,把这种不固定的路由形势映射到同一个组件,例如:一个User组件,不同的ID表示不同的用户,即/user/1、/user/2、/user/3,这些不同用户所对应的路由,我们都希望用一个User组件来渲染。vue-router中提供了动态路径参数来实现这种需求,动态路径参数写法:

    routes: [
    // 动态路径参数 以冒号开头
      { 
        path: '/user/:id', 
        component: User 
      }
    ]
    

    这里的id类似于一个变量,id可以是1、2、3等具体的值
    声明式导航:

    
    

    编程式导航:

    goToDetail(item) {
       this.$router.push({
         name: `Detail`,
         params: {
            id: item.id
         }
       });
    }
    

    路由配置:
    ?用的是正则表达式,?代表零次或者一次,如果不加问号的话,则id值必须传

    routes: [
      {
        path: '/user/:id?',
        component: User
      }
    ]
    

    如何监听/响应动态参数的变化?
    方式1: 使用 beforeRouteUpdate 钩子函数

    beforeRouteUpdate (to, from, next) {
      //to和$route的信息差不多
      this.userInfo = this.userList.filter((item) => to.params.id === item.id)[0]
      next()
    }
    

    方式2: 在组件中对 $route 进行 watch(监听)

    watch: {
      $route () {
        console.log(this.$route)
      }
    }
    

    路由信息对象$route解析:

    • path 对应当前路由的路径
    • params 动态路由参数
    • query url查询参数
    • hash 当前路由的hash值
    • fullPath 完整的url路径,包含查询参数和hash
    • matched 包含当前路由的所有嵌套路径片段的路由记录
    • name 当前路由的名称

    13.路由组件传参

    路由和对应组件之间的传参:
    在组件中使用 $route 会使之与其对应路由形成高度耦合,从而使组件只能在某些特定的 URL 上使用,限制了其灵活性,我们需要做的是通过传参将组件与路由解耦,使得组件的使用更加灵活,这里需要使用到props

    路由配置里面我们需要改成这样
    只要是对应的路由中设置了props: true,动态路由参数就会自动作为一个属性,传到对应的组件中去,在组件中用porps进行接收之后就可以通过this.属性来使用动态路由中的参数

    routes: [
      {
        path: '/user/:id?',
        component: User,
        props: true
      
      }
    ]
    

    在组件的js代码中通过props接收

    props: ['id'],
    

    14.记录滚动位置

    在路由配置文件中通过以下代码,当导航到新路由时,通过设置滚动行为让页面滚动到你想要的位置。

    const router = new VueRouter({
      routes: [...],
      scrollBehavior (to, from, savedPosition) {
               //to-->即将进入的路由
               //from--->从哪里来
               //savePosition--->保存滚动的位置信息
        // 如果检测到记录的位置信息,我们就返回这个位置信息
               //如果没有检测到记录的位置信息,我们就返回顶部
            if(savePositon){
                return savePositon
                }else{
                     return {x:0,y:0}     
                }
      }
    }
    

    注意:
    这个功能只在支持 history.pushState 的浏览器中可用,和mode没有关系。
    高版本的浏览器可以不用写上面那些代码,可以自动实现。

    15.vue-router中的全局钩子函数

    在vue-router中,路由发生变化,我们可以做一些事情,例如:可以决定是否进入导航,可以决定跳转到哪里,官方文档中又叫做导航守卫。
    首先来看一个全局的钩子函数,官方文档中叫做注册一个全局的前置守卫,使用router.beforeEach方法来实现

    router.beforeEach(() => {
      console.log('beforeEach执行了....')
    })
    

    这里的beforeEach可以理解为在每个导航进入之前挂的一个钩子,会在每个导航进入之前出发,在beforeEach里面就可以做一些事情,例如,阻止进入导航,执行上面的代码,会发现我们点击相应的导航,对应的组件并不能渲染出来了,罪魁祸首就是这个beforeEach。
    当我们把代码稍作修改:

    router.beforeEach((to, from, next) => {
      console.log('beforeEach执行了....')
      next()
    })
    

    组件就可以正常渲染了。
    每个路由钩子函数接收三个参数:

    to: [Route]: 即将要进入的目标 路由对象
    from: [Route]: 当前导航正要离开的路由
    next: [Function]: 一定要调用该方法来 resolve 这个钩子
    

    这里的next是一个函数,如果不调用next方法,就不会进入下一个钩子,我们就可以用它来实现跳转或者取消
    在写具体跳转或者取消案例之前,插播一个前置知识点:路由元信息
    路由元信息就是给每条路由记录配置一个meta字段,字段配置好后可以在需要的地方拿出来使用
    配置示例:

    {
      path: '/',
      components: {
        default: Home,
        a: HomeSider,
        b: HomeMain
      },
      //上面的这个对象称为一个路由记录
      //meta我们设置一个全局的,也可以在单个的路由记录中单个设置
      meta: {
        isLogin: true
      }
    }
    

    我们可以从钩子函数的参数中拿到meta字段值

    router.beforeEach((to, from, next) => {
      console.log('beforeEach执行了....')
      if (to.meta.isLogin) {
        next()
      } else {
        next(false)
      }
    })
    

    next函数中传入false就表示不进入导航,我们在meta字段中配置了isLogin,在使用的时候通过to.meta.isLogin 取出来做判断,如果值是true就执行next 如果值是false就执行next(false)
    next函数内还可以传入一个路由地址,会自动跳到改地址,我可以把上面代码稍作修改

    router.beforeEach((to, from, next) => {
      console.log('beforeEach执行了....')
      if (to.meta.isLogin) {
        next()
      } else {
        next('/login')
      }
    })
    

    除了在导航进入之前有一个钩子函数,在导航进入之后也有一个钩子函数,叫做afterEach,使用方法和beforeEach类似, 因为afterEach执行时已经进入到导航了,所以没有第三个参数next

    router.afterEach((to, from) => {
      console.log('afterEach执行了....')
      // 判断是否有title字段
      if (to.meta.title) {
        window.document.title = to.meta.title 
      } else {
        window.document.title = 'hello'
      }
    })
    

    16.vue-router中写到路由记录里的钩子函数

    beforeEnter 在进入导航前被调用,需要在路由记录里面配置

    {
      path: '/course',
      component: Course,
      meta: {
        isLogin: false,
        title: '好好学编程'
      },
      beforeEnter (to, from, next) {
        console.log('beforeEnter被执行了')
      }
    },
    

    17.写在组件内部的路由钩子函数

    1.beforeRouteEnter, 在导航进入前被调用,在这个函数里面不能拿到this,因为即将被渲染的组件还没被创建

    beforeRouteEnter (to, from, next) {
    console.log('user组件中的beforeRouteEnter执行了')
    next()
    }
    

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

    beforeRouteUpdate (to, from, next) {
      console.log('user组件中的beforeRouteUpdate执行了')
      next()
    }
    

    3.beforeRouteLeave,导航离开该组件的对应路由时调用,可以访问组件实例 this

    beforeRouteLeave (to, from, next) {
      console.log('user组件中的beforeRouteLeave执行了')
      next()
    }
    

    18.路由切换的动画效果

    vue中封装了一套transtion组件,可以提供过渡效果

    
      
    
    

    通过过渡css类名的方式来设置过渡效果
    过渡的类名称有:

    • v-enter:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。
    • v-enter-active:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。
    • v-enter-to: 2.1.8版及以上 定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时 v-enter 被移除),在过渡/动画完成之后移除。
    • v-leave: 定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。
    • v-leave-active:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。
    • v-leave-to: 2.1.8版及以上 定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时 v-leave 被删除),在过渡/动画完成之后移除。
      其中,v- 这个前缀是可以自定义的,例如:
    .fade-enter {
      transform: translateX(-100%);
      opacity: 0;
    }
    .fade-enter-to {
      transform: translateX(0);
      opacity: 1;
    }
    .fade-enter-active {
      transition: 1s;
    }
    .fade-leave {
      transform: translateX(0);
      opacity: 1;
    }
    .fade-leave-to {
      transform: translateX(100%);
      opacity: 0;
    }
    .fade-leave-active{
      transition: 1s;
    }
    

    我们把类名称的前缀自定义成了“fade-”, 这里需要注意的是前缀可以自定义,但是后面的enter、enter-to不能自定义,自定义类名称后,需要在transition组件上加name属性

    
      
    
    

    上面代码中,我们发现有个mode属性,这个属性表示设置过渡的模式, out-in,通俗的说就是先离开,再进入,同时还有另一种模式,in-out,先进入,再离开

    你可能感兴趣的:(详解Vue-router)