vue-router安装配置和使用

发布时间 2023-07-21 09:42:10作者: hhhhuaz
title: vue-router安装配置和使用
date: 2023-07-20 17:55:19
tags:
- vue
categories:
- 工程
- 前端
top:

vue-router安装配置和使用

学习vue的第六天,学到了用插件vue-router来实现vue单页面应用的开发,实现页面的路由跳转。

以下是个人理解,如有错误请指正。

vue-router是vue官方的一个路由管理插件,用于实现页面上的路由跳转,可以很方便的实现单页面应用的开发。

vue-router安装和配置

安装

直接使用npm命令安装就可以了,这里有一个点是如果使用的是vue2那么应该安装vue-router3版本,后面的vue-router4版本是为vue3准备的,如果强行安装的话会出现报错。

npm install vue-router@3

安装速度挺快的,那么既然说是vue的一个插件也就是说应该是跟vuex差不多,需要用vue.use将插件使用到vue上。

配置

首先在src文件夹下面创建router文件夹,为了编写路由的配置,在router文件加下创建index.js文件,直接在index.js文件中编写即可。

首先将下载的vue-router引入,通过new方法创建一个VueRouter的对象,创建时传入的是一个对象参数,对象中是要用的配置信息,创建完毕之后将实例export暴露出即可。

  • mode:这个参数配置是设置路由使用hash模式还是history模式。
    • hash模式:在url路径中会出现一个/#/这样的符号,前端的路由跳转都写在了这个符号后面,像后端请求的时候不会将/#/后面的内容发出去。最直接的就是当看到页面的某个地方时点击了浏览器的刷新,hash模式会成功刷新并展示页面,而history模式会出现url请求错误。
    • history模式:url直接展示,当向后端发送请求时会将全部的url发送。解决方法,需要后端协助解决,判断请求的url是否属于前端。
  • routes:这个就是最主要的配置,也就是配置页面上路由跳转的配置项。
    • routes的value是一个数组,数组中是每一个路由规则的对象。
    • 对象中可以配置的选项:
      • path:写的是跳转的路由,也就是在url中拼接的部分
      • component:当跳转这个路由时会展示的组件,填写的是组件的name
      • name:这个是给路由命名,在router-link标签中的to属性中可以通过name来寻找到这个特定的路由。
      • children:子路由,该路由下的一些子路由,在url上的体现就是在该路由的path下再拼接一个path,这里要注意的是,只有一级路由的path要加/,子路由中的path项都不需要加/

router/index.js文件

// 该文件专门用于创建整个应用的路由器
import VueRouter from "vue-router";
import About from "../pages/About";
import Home from "../pages/Home";
import News from "../pages/News";

// 创建一个路由器
const router = new VueRouter({
    mode:"hash",
    routes:[
        {
            name:'about',
            path:'/about',
            component:About
        },
        {
            name:'home',
            path:'/home',
            component:Home,
            children:[
                {
                    name:'news',
                    path:'news',
                    component:News,
                }
            ]
        }
    ]
})

export default router

创建完router文件夹并编写完配置文件之后,需要在main.js中将router插件加载到vue上。这里有一个点是router在Vue创建时传入对象中时只能用router来命名,是官方固定的,如果写其他命名就会无效。

main.js文件

import Vue from "vue";
import App from "./App.vue";
import VueRouter from "vue-router";
// 引入router
import router from './router'
// 关闭生产提示
Vue.config.productionTip = false;

Vue.use(VueRouter)

new Vue({
    el: "#app",
    router,
    render: h => h(App),
})

配置完启动项目,在浏览器进去8080后url会自动加上一个/#/符号,就说明路由已经配置完成。

image-20230720195604228

vue-router使用

使用vue-router首先应该是将组件的路由转发规则配置好,也就是在router文件下的index.js文件中,在routes的配置数组中写的每一个对象就是每一条路由规则,如上面示例的index.js文件中,创建了两个一级路由,一个二级路由。

下方是App.vue中将配置的路由应用到组件中,使用的是router-link标签,标签中有一个to属性,填的就是路由文件中配置的path,也可以写成:to属性,然后传入对象,对象中可以传路由中的name值找到相应的路由。这里router-link应该和router-view一起用,前者是跳转路由,后者是路由指向的组件展示的地方,有点类似与插槽。

App.vue

<template>
  <div>
    <router-link to="/about" >About</router-link><br><br>
    <router-link to="/home" >Home</router-link>
    <hr>
    <router-view></router-view>
  </div>
</template>

<script>
    import About from './pages/About';
    import Home from './pages/Home';

    export default {
        name: "App",
        components:{
          About,
          Home
        }
    }
</script>
  • keep-alive标签

    • 组件间通过路由切换之后会自动销毁,考虑到有些组件可能会频繁的切换所以可以通过一个标签将标签包裹之后可以实现组件切换之后不被销毁,下次激活时仍然可以使用同时不需要再次挂载。

    • include属性:属性可以传递一个字符串,就是表明当跳转后该组件不会被销毁,也可以传递一个数组,表示数组中的组件都不会销毁,当然如果不传递参数,或者说不指定include那么就是所有的组件都不会销毁。

      <keep-alive include="News">
          <router-view></router-view>
      </keep-alive>
      
      <keep-alive :include="['News', 'Messages']">
          <router-view></router-view>
      </keep-alive>
      
  • router-view标签

    • 展示router-link路由链接的组件的位置,类似于插槽,提前占位。
  • router-link标签:

    • replace属性,布尔类型:

      • 默认为false,设置replace属性之后会默认调用router.replace()方法而不是router.push(),不会留下history历史记录。

        :to="{
            path:'/home',
            replace,
        }"
        
    • active-class属性,string类型:

      • 设置当链接激活时要添加到标签上的css类名

        :to="{
            path:'/home',
            replace,
            active-class='active',
        }"
        
    • to属性(string类型)指定点击之后要跳转的路由

      • 简单的路由跳转,不传参

        • 字符串写法

          to="/home"
          to="/home/news"
          
        • 对象写法

          // 传path
          :to="{
              path:'/home',
          }"
          // 传name
          :to="{
              name:'home',
          }"
          
      • 传递query参数,在组件中可以通过this.$route.query拿到数据

        • 字符串写法

          :to="`/home/messages/detail?id=${m.id}&title=${m.title}`"
          
        • 对象写法

          // 也可以通过name来寻找路由替换path。
          :to="{
              path:'/home/messages/detail',
              query:{
                  id: m.id,
                  title: m.title
              }
          }"
          
      • 传递params参数,在组件中可以通过this.$route.params拿到数据

        • 字符串写法

          :to="`/home/messages/detail/${m.id}/${m.title}`"
          
        • 对象写法

          // 传递params参数必须用name属性
          :to="{
              name:'detail',
              params:{
                  id: m.id,
                  title: m.title
              }
          }"
          // router中的配置需要将path修改,添加占位符
          {
              name:'detail',
              path:'detail/:id/:title',
              component:Detail
          }
          
  • router/index.js配置

    • 通过配置项将参数以props形式传递,在组件中只需要通过props方式接收传递的参数即可,与组件间props传参接收一样。

      • 第一种,props值为对象,该对象中的key-value最终都会以props形式传到Detail组件中

        {
            name:'detail',
            path:'detail',
            component:Detail,
                
            props:{id:'666', title:'888'}
        }
        
      • 第二种,props值为布尔值,如果为真,会将收到的params参数以props形式传到Detail组件中

        {
            name:'detail',
            //params传参需要配置path占位
            path:'detail/:id/:title',
            component:Detail,
        
            props:true
        }
        
      • 第三种,props为函数,函数有一个接收参数就是$route,该函数返回值对象中每一组key-value都会以props形式传到Detail组件中,这里可以用query传参,也可以用params传参(注意params传参要修改path占位),最后props会将数据处理传递到组件的props属性中。

        {
            name:'detail',
            path:'detail',
            component:Detail,
            
            props($route){
                return {id:$route.query.id,title:$route.query.title}
            }
        }
        
  • 编程式路由导航

    • 由于在程序编写中触发路由跳转的位置不一定每次都可以写route-link标签,可能也是个按钮点击之后跳转路由,下面的编程式路由导航就是方便自定义编写。

    • 这里用到两个router上的函数触发跳转,以按钮点击跳转为例

      • push,即保存浏览器history历史记录,点击触发回调函数,函数中可以通过this找到$router中有一个push方法,这个方法就是触发路由跳转,传入参数为一个对象,可以理解为与router-link中的to传入对象一致。

        pushShow(m){
            this.$router.push({
              name:'detail',
              query:{
                id: m.id,
                title: m.title
              }
            })
        },
        
      • replace,即不保存浏览器history历史记录,点击出发回调函数,函数中可以通过this找到$router中有一个raplace方法,这个方法就是触发路由跳转,传入参数为一个对象,可以理解为与router-link中的to传入对象一致。

        replaceShow(m){
            this.$router.replace({
              name:'detail',
              query:{
                id: m.id,
                title: m.title
              }
            })
        },
        
  • 两个生命周期钩子

    • 当组件通过路由跳转后,原先展示的组件就会自动销毁,所以上方提到了keep-alive标签,可以保证组件在路由跳转之后不被销毁,这样就可能会出现一些问题,当组件中创建了计时器,调用生命周期钩子beforeDestroy时将计时器销毁,可是当在keep-alive中组件不会销毁,这时销毁的生命周期构子就不会被调用,可是计时器应该在组件不展示时取消掉,否则在后台会一直占用资源,这里就引出了下面的两个生命周期钩子用来解决这个问题。
      • activated()这个会在组件激活时调用也就是组件从消失状态--->用户眼前时。
      • deactivated()这个会在组件失火时调用也就是组件从用户眼前--->消失状态时。
  • 路由守卫

    • 全局路由守卫

      全局路由守卫有两个,当路由跳转时会自动触发。

      • 全局前置路由守卫:在路由跳转之前调用,如果回调函数中自己写的校验逻辑未通过则可以不调用next函数向下跳转,即不允许跳转。

      • 接收为一个回调函数,回调函数中接收三个参数,to:要跳转向哪个路由,from:从哪个路由跳转来,next:一个函数,当调用next时路由会正常像下一步跳转,这里可以做一些路由检测工作,如果检测未通过就不调用next,不允许跳转。

        router.beforeEach((to, from, next)=>{
            console.log("beforeEach");
            next()
        })
        
      • 全局后置路由守卫:在路由跳转之后调用,也就是此时已经跳转完毕,组件也已经展示了,这时可以做一些跳转之后的逻辑,比如页签图标什么的。

      • 接收为一个回调函数,回调函数中接收两个参数,to:要跳转向哪个路由,from:从哪个路由跳转来,没有next函数了,因为路由已经跳转完毕。

        router.afterEach((to, from)=>{
            console.log("afterEach");
        })
        
    • 独享路由守卫

      • 只有一个,在routes配置中编写,独享路由守卫也是在路由跳转之前调用,不过是在全局前置路由守卫之后调用,作用可以和全局前置路由守卫一样,不过独享路由守卫只有配置过的路由在跳转的时候才会调用。

      • 接收为一个回调函数,回调函数中接收三个参数,to:要跳转向哪个路由,from:从哪个路由跳转来,next:一个函数,当调用next时路由会正常像下一步跳转,这里可以做一些路由检测工作,如果检测未通过就不调用next,不允许跳转。

        beforeEnter:(to, from, next)=>{
            console.log("beforeEnter");
            next()
        }
        
    • 组件内路由守卫:组件内路由守卫写在组件中。

      • 组件进入前守卫:当点击路由跳转时会调用该守卫,如果前面的守卫都有写的话,调用顺序是在独享路由守卫之后。

      • 接收为一个回调函数,回调函数中接收三个参数,to:要跳转向哪个路由,from:从哪个路由跳转来,next:一个函数,当调用next时路由会正常像下一步跳转,这里可以做一些路由检测工作,如果检测未通过就不调用next,不允许跳转。

        beforeRouteEnter(to, from, next){
            console.log("beforeRouteEnter");
            next()
        },
        
      • 组件离开前守卫:该守卫与其他守卫不太一样,该守卫的调用时机是:当前组件在展示,点击路由要跳转其他组件离开时会调用该组件,该组件也可以阻止跳转,因为接收了next参数。

      • 接收为一个回调函数,回调函数中接收三个参数,to:要跳转向哪个路由,from:从哪个路由跳转来,next:一个函数,当调用next时路由会正常像下一步跳转。

        beforeRouteLeave(to, from, next){
            console.log("beforeRouteLeave");
            next()
        }
        
    • 当五个路由守卫都写的时候调用顺序如下:

      image-20230721091557845

      两个全局守卫会在每次路由跳转时都会调用。

  • 路由元信息$route.meta

    • 可以在定义路由时在对象中增加meta参数,参数传递为一个对象,对象中可以是一些认证信息等 ,当用户点击跳转路由时可以在守卫中取出meta中的信息与用户localstorage中的信息对比,如果认证通过则可以完成路由跳转。

      {
          name:'news',
          path:'news',
          component:News,
          meta:{token:'11111'},
          // 独享路由守卫,在全局前置后,全局后置前调用
          beforeEnter:(to, from, next)=>{
              console.log("beforeEnter");
              next()
          }
      },