路由vue-router从入门到精通(vue2)

前端路由的概念与原理

1.什么是路由

路由(英文: router)就是对应关系

2.SPA与前端路由

SPA指的是一个web网站只有唯一的一个HTML页面,所有组件的展示与切换都在唯一的一个页面内完成。

此时,不同组件之间的切换需要通过前端路由来实现。

结论:在 SPA 项目中,不同功能之间的切换,要依赖于前端路由来完成!

3. 什么是前端路由

通俗易懂的概念:Hash 地址组件之间的对应关系.

4. 前端路由的工作方式

① 用户点击了页面上的路由链接

② 导致了 URL 地址栏中的 Hash 值发生了变化

③ 前端路由监听了到 Hash 地址的变化

④ 前端路由把当前 Hash 地址对应的组件渲染都浏览器中

基础配置

1. 什么是 vue-router

vue-router是vue.js官方给出的路由解决方法,他只能结合vue项目进行使用,能够轻松管理SPA(单页面)项目中的切换

不同的vue版本对应不同的路由版本,

Vue2版本对应VueRouter3.x版本      

Vue Router  (vue-router3官网网站)

vue3版本对应VueRouter4.x版本

Vue Router | Vue.js 的官方路由   (vue-router4官方网站)

2. vue-router 安装和配置的步骤

① 安装 vue-router 包

② 创建路由模块

③ 导入并挂载路由模块

④ 声明路由链接和占位符

2.1 在项目中安装 vue-router

在 vue2 的项目中,安装 vue-router 的命令如下:

npm i vue-router@3.5.2 -S

2.2 创建路由模块

在 src 源代码目录下,新建 router/index.js 路由模块,并初始化如下的代码:


import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

const router = new VueRouter({
  routes: [
    { path: '/', redirect: '/home' },  
  ]
})

export default router

2.3 导入并挂载路由模块

在 src/main.js 入口文件中,导入并挂载路由模块。示例代码如下:

import Vue from 'vue'
import App from './App.vue'

import router from '@/router'

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

2.4 声明路由链接占位符

在 src/App.vue 组件中,使用 vue-router 提供的 <router-link> 和 <router-view> 声明路由链接和占位符:

<template>
  <div>
    <h1>App组件</h1>

    <!-- 定义路由链接 -->
    <router-link to="/home">首页</router-link>
    <router-link to="/movie">电影</router-link>
    <router-link to="/about">关于</router-link>
    <hr>

    <!-- 定义路由占位符 -->
    <router-view></router-view>
  </div>
</template>

其实使用<a>链接也行,如<a href="#/home">首页</a> 但更推荐使用<router-link> 并且这样不需要写#号,在浏览器控制台看到的还是<a>链接

3. 声明路由的匹配规则

在 src/router/index.js 路由模块中,通过 routes数组声明路由的匹配规则。示例代码如下:


//导入需要的组件
import Vue from "vue";
import VueRouter from "vue-router";

// 1. 告诉Vue要使用VueRouter
Vue.use(VueRouter);

//创建一个路由规则数组
const routes = [
  { path: "/", component: () => import("@/views/About.vue") },
  { path: "/about", component: () => import("@/views/About.vue") },
]


// 3. 创建路由实例  将路由规则添加到实例中
const router = new VueRouter({
  routes:routes
});

4.路由模式 (hash/history)

路由有两种工作模式,分别是:hash 和 history

设置路由模式

路由模式是在路由实例中mode参数配置的,默认是是hash

// 3. 创建路由实例
const router = new VueRouter({
  mode: "history", // 使用 history 模式
  routes: routes,
});

hash 模式

router默认的路由模式就是hash,# 就是代表 hash ,后面就是 hash 值

优缺点:

  • 地址中永远带有#号,不美观
  • 若以后将地址通过第三方手机app分享,若app效验严格,则地址会被标记为不合法
  • 兼容性较好
  • 注意:# 后面的值都是不发给服务器的

history 模式

history 是没有 # 号的

    • 地址干净美观
    • 兼容性和hash模式相比略差
    • 应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题
    • (比如 http://localhost:8080/home/message,本来是 http://localhost:8080,点击去到 message 页面时,路径就变了,在刷新的时候路径还是 http://localhost:8080/home/message,/home/message 也会发给服务器,可人家只认识 http://localhost:8080,hash 就不会这样了,http://localhost:8080/#/home/message,因为 # 后面的都不会发给服务器)

    hash 和 history 的区别

    1. 对于一个url来说,什么是hash值?——#及其后面的内容就是hash值
    2. hash值不会包含在HTTP请求中,即:hash值不会带给服务器

    5.核心配置字段

    • path:路由路径

    path用于定义路由路径,可接受固定参数与动态参数,

    const routes = [
      {
        path: '/',           // 根路径
        component: Home
      },
      {
        path: '/about',      // 固定路径
        component: About
      },
      {
        path: '/contact-us', // 带连字符的路径
        component: Contact
      },
    {
      path: '/user/:id',     // :id 是动态参数
      component: UserDetail
    },{  //多个参数
      path: '/category/:categoryId/product/:productId',
      component: ProductDetail
    }
    ]
    • component对应组件

    component 字段用于将路由路径映射到具体的 Vue 组件。

    直接导入组件

    import Home from '@/views/Home.vue'
    import About from '@/views/About.vue'
    
    const routes = [
      {
        path: '/',
        component: Home
      },
      {
        path: '/about',
        component: About
      }
    ]

    基础懒加载组件(推荐)

    const routes = [
      {
        path: '/',
        component: () => import('@/views/Home.vue')
      },
      {
        path: '/about',
        component: () => import('@/views/About.vue')
      }
    ]

    配置多个组件

    const routes = [
      {
        path: '/settings',
        components: {        // 注意是 components(复数)
          default: () => import('@/views/SettingsMain.vue'),
          sidebar: () => import('@/components/SettingsSidebar.vue'),
          header: () => import('@/components/SettingsHeader.vue')
        }
      }
    ]

    • name命名路由

    • components命名视图(多组件)

    • redirect重定向

    • 动态从定向

    • alias(别名)

    • props(将params作为props传递)

    • 静态props   函数形式   

    • children嵌套路由

    • meta路由元信息

    三、vue-router 的常见用法

    声明式导航

    在浏览器中,点击链接实现导航的方式,叫做声明式导航。例如:

    • 普通网页中点击 <a> 链接、vue 项目中点击 <router-link> 都属于声明式导航

    vue中创建声明式导航

    <router-link to="/">首页</router-link> |
    <router-link to="/about">关于</router-link> |

    编程式导航

    在浏览器中,调用 API 方法实现导航的方式,叫做编程式导航。例如:

    • 普通网页中调用 location.href 跳转到新页面的方式,属于编程式导航

    vue中使用编程式导航栏

    this.$router.push(‘hash 地址’)

    路径路由

    直接使用路径字符串进行定义和导航的路由。

    定义路径路由

      // 命名路由
      const routes = [ 
          {
            //纯路径路由
            path: "/user",
            component: () => import("@/views/User.vue"),
          },{
             //动态路径路由
             // :id 是参数占位符,  在跳转路径/user  后的参数为id, 没有参数会找不到页面
             path: '/user/:id',       
             component: UserDetail
          },{
            //动态路径路由
            // :id 是参数占位符,  在跳转路径/user  后的参数为id, 加上?没有后面参数也可以
            path: '/product/:id?',        // ? 表示可选
            component: ProductDetail
          },{
            //动态路径路由
            //这是两个站位符号, 路径是/category/路径/路径,  没有会找不到页面
            path: '/category/:type/:id',  //多个参数
            component: CategoryDetail
          },{
            //命名路由+ 路径路由
            path: '/category', 
            name:'category'
            component: CategoryDetail
          },{
            //纯命名路由
            name:'category'
            component: CategoryDetail
          }
      ]

    使用路径路由(声明式)

    <!-- 声明式  使用路径路由 -->
    <router-link to="/user/123">用户资料</router-link>

    使用路径路由(工程式)

    // 使用路径方式
    router.push('/user')
    router.push({ path: '/user' }) 

    路径路由跳转传参

    注意:路径路由进行跳转传参需要使用占位符, 这个站位符需要在路由定义的时候就确定, 以上面的路由定义为列:

    router.push('/user/123')        //必须要有后面的路径
    
    router.push('/product/123')    //可有可无
    router.push('/product')        //可有可无
    
    router.push('/category/111/222')        //需要有两个参数
    
    this.$router.push({ path: "/user/123", query: { id: 1 } });

    获取路径路由的传参

    $route.params.站位名称

    命名路由

    命名路由是 Vue Router 中的一个功能,它允许你为路由规则起一个唯一的名称,然后通过这个名称来导航,而不是通过硬编码的路径路径。

    定义命名路由

      // 命名路由
      const routes = [ 
          {
            name: "User",
            component: () => import("@/views/User.vue"),
          },
      ]

    使用命名路由(声明式)

    <!-- 声明式  使用命名路由 -->
    <router-link :to="{ name: 'User', query: { id: 123 }}">
      用户资料
    </router-link>

    使用命名路由(工程式)

    // 使用命名路由方式 + 传参
    router.push({ name: 'User'})

    命名路由传参

    router.push({ name: 'User',query:{id: 123}})

    关于路由传参的重点

    其实路由的配置分很多种, 纯路径路由,动态路径路由, 纯命名路由,命名路由+路径路由,  命名路由+动态路径路由

    很多小伙伴看到这个里可能就有点懵了,我们到底要用那种路由呢?到底要用那种传参呢?其实刚开始的时候我也没搞清楚,

    现在先了解一下params 和 query

    params与query了解

    这两个都是进行传参的,但是有什么不同呢

    params

    params也是进行传参的,但是是属于路径的一部分,需要再路由中定义占位符才可以使用

    • 位置:路径的一部分
    • URL示例:/user/123
    • 路由配置:需要预先定义
    • 必选/可选:必选(除非标记为可选)
    • 获取方式:$route.params

    注意:

    根据我们上面的传参介绍肯定有小伙伴会写这样的代码

    this.$router.push({paht:'/user',params:{id:'1111'}})

    这样的代码是错误的,我也再路由中定义占位符了呀, params为什么没有替换掉站位符呢?

    当提供 path 时,Vue Router 认为路径已经确定,不再进行占位符替换,直接忽略 params

    this.$router.push({
      path: '/user',      // Vue Router 看到这个...
      params: { id: '1111' }  // ...就认为这个不需要了
    })

    所以我们再使用params的时候要使用命名路由

    this.$router.push({
      name: 'user',
      params: { id: '1111' }  
    })

    核心原理:命名路由的"路径模板替换"机制

    当使用命令路由的时候,vue-router会根据name查找路由配置,找到path,将params进行替换

    query

    query也是进行传参的,但是是属于? 问号后面的部分,用于向页面传递额外的数据。

    • 位置:URL 中 ? 后面
    • 格式:key=value,多个用 & 连接
    • 路由配置:无需在路由中预先定义
    • 必选/可选:完全可选,可以有任意多个
    • 获取方式:$route.query

    所有的编程式导航都可以使用 query 参数。

    在初学的时候很多小伙伴进行传参就会搞迷糊,为什么有的使用query有的params,

    路由导航API

    下面我们来了解一下常用的路由导航Api

    • router.push:添加新路由记录

    • router.replace:替换当前路由

    • router.go : 前进后退

    • router.back : 后退

    router.push

    使用语法:params需要在路径路由中设置占位符

    // 字符串路径
    router.push('/home')
    
    // 对象形式
    router.push({ path: '/home' })
    
    // 命名路由
    router.push({ name: 'home' })
    
    // 带参数
    router.push({ path: '/user/123' })
    router.push({ name: 'user', params: { id: 123 } })
    router.push({ path: '/user', query: { id: 123 } })

    router.replace

    替换当前路由

    // 替换当前路由,不添加新的历史记录
    router.replace('/home')
    router.replace({ path: '/home' })
    router.replace({ name: 'home' })

    router.go

    // 前进 1 步,相当于 history.forward()
    router.go(1)
    
    // 后退 1 步,相当于 history.back()
    router.go(-1)
    
    // 后退 3 步
    router.go(-3)
    
    // 前进 2 步
    router.go(2)

    router.back

    后退

    // 等同于 router.go(-1)
    router.back()

    导航守卫

    1. 全局守卫

    • 全局前置守卫

    全局前置守卫是在路由跳转之前执行的守卫,是最常用的导航守卫之一。

    基本语法

    //router为VueRouter的实例
    router.beforeEach((to, from, next) => {
      // 守卫逻辑
    })

    参数说明

    • to: 即将要进入的目标路由对象

    • from: 当前导航正要离开的路由对象

    • next: 函数,必须调用才能继续导航

    next 函数的用法

    // 1. 放行
    next()
    // 2. 中断导航,停留在当前页面
    next(false)
    // 3. 跳转到指定路径
    next('/login')
    next({ path: '/login' })
    // 4. 传递错误
    next(new Error('导航失败'))

    • 全局解析守卫

    • 全局后置钩子

    2. 路由独享守卫

    3. 组件内守卫

    1. 路由重定向

    路由重定向指的是:用户在访问地址 A 的时候,强制用户跳转到地址 C ,从而展示特定的组件页面。

    通过路由规则的redirect属性,指定一个新的路由地址,可以很方便地设置路由的重定向:

    const router = new VueRouter({
      routes: [
        //当用户访问 / 的时候,  通过redirect属性跳转/home对应的路由规则
        { path: '/', redirect: '/home' },   
        { path: '/home', component: Home },
        { path: '/movie', component: Movie },
        { path: '/about', component: About }
      ]
    })

    当hash为/时就默认跳到home组件,防止hash为/时什么也没显示,场景就是刚进入页面时,默认显示首页

    补充:{ path: ‘*’, component: NotFound } 可在最后加上,表示上面的路由都没有匹配到时会展示此组件

    2. 嵌套路由

    通过路由实现组件的嵌套展示,叫做嵌套路由。

    比如about组件中还有两个需要显示的子组件

    2.1 声明子路由链接**和子路由占位符

    在 About.vue 组件中,声明 tab1 和 tab2 的子路由链接以及子路由占位符。示例代码如下:

    <template>
      <div clsss="about-container">
        <h1>about组件</h1>
    
    
        <!-- 在关于页面中声明了两个子路由链接 -->
        <router-link to="/about/tab1">tab1</router-link>
        <router-link to="/about/tab2">tab2</router-link>
        <br>
    
        <!-- 声明子路由占位符 -->
        <router-view></router-view>
        
      </div>
    </template>

    2.2 通过 children 属性声明 子路由规则

    在 src/router/index.js 路由模块中,导入需要的组件,并使用 children 属性声明子路由规则:

    import Tab1 form '@/components/tabs/Tab1.vue'
    import Tab2 form '@/components/tabs/Tab2.vue'
    
    const corter =new VueRouter({
        router:[
             {
               path:'/about',
               component:About,
               chlidren:[
                   {  path:'tab1',component:Tab1   },
                   {  path:'tab2',component:Tab2   }
                ]
             }
        ]
    })

    注意:子路由的 path 不需要加 /

    3.3 使用 props 接收路由参数

    为了简化路由参数的获取形式,vue-router 允许在路由规则开启 props 传参。示例代码如下:

    //在定义路由规则时,声明  props:true 选项
    //即可在Movie组件中 一props的形式接收到路由规则匹配到的参数项
    { path : '/movie/:id' , component:Movie, props:true}
    
    <teplate>
      <!-- 直接使用props接收路由的参数>
      <h3>组件 --  {{id}}</h3>
    </teplate>
    
    <script>
        export default { props :['id'] }
    </script>

      五、导航守卫

      导航守卫可以控制路由的访问权限。示意图如下:

      5.1 全局前置守卫

      每次发生路由的导航跳转时,都会触发全局前置守卫。因此,在全局前置守卫中,程序员可以对每个路由进行访问权限的控制:

      //创建路由实例
      const router = new VueRouter({ ...  })
      
      //调用路由实例 beforeEach 方法,即可声明 ' 全局前置守卫 '
      //每次发生路由导航跳转时,都会自动触发fn这个 '回调函数'
      
      router.beforeEach(fn)

      小白注意:第2行后面并不是三个点,是配的路由,只是这里省略罢了

      5.2 守卫方法的 3 个形参

      全局前置守卫的回调函数中接收 3 个形参,格式为:

       // 创建路由实例对象
       const router = new VueRouter({ ... })
      
       // 全局前置守卫
       router.beforeEach((to, from, next)=>{
        // to 是将要访问的路由的信息对象
        // from 是将要离开的路由的信息对象
        // next 是一个函数,调用 next()表示放行,允许这次路由导航
       })

      5.3 next 函数的 3 种调用方式

      参考示意图,分析 next 函数的 3 种调用方式最终导致的结果:

       当前用户拥有后台主页的访问权限,直接放行:next()

      当前用户没有后台主页的访问权限,强制其跳转到登录页面:next(‘/login’)

      当前用户没有后台主页的访问权限,不允许跳转到后台主页:next(false)

      5.4 控制后台主页的访问权限

          router.beforeEach((to, from, next) => {
      
            if (to.path === '/main') {
              const token = localStorage.getItem('token')
              if (token) {
                next()//访问的是后台主页,且有token 的值
              } else {
                next('/login')//访问的是后台主页,但是没有 token 的值
              }
      
            } else {
              next()//访问的不是后台主页,直接放行
            })
        

      当如果很多个都要进行导航守卫时可以使用如下做法:

      // 全局前置守卫
      router.beforeEach((to, from, next) => {
      	// 要进行导航守卫的路径值
          const pathArr = ['/home','/home/users', '/home/rights']
          if (pathArr.indexOf(to.path) !== -1) {
              const token = localStorage.getItem('token')
              if (token) {
                  next()
              } else {
                  next('/login')
              }
          } else {
              next()
          }
      })
      

      还有一种写法就是给每一个路由添加 meta 配置项,通过meta里的真假值来判断是否需要进行判断

           { 
              path: 'users',
              component: Users,
              meta: { isAuth: true },
            },
            ...
            
      // 全局前置守卫
      router.beforeEach((to, from, next) => {
          if (to.meta.isAuth) { // 判断是否需要进行导航守卫
              const token = localStorage.getItem('token')
              if (token) {
                  next()
              } else {
                  next('/login')
              }
          } else {
              next()
          }
      })
      

      六、全局后置钩子

      • 每次发生路由的跳转之后都会触发全局后置钩子,用的比较少
      • 但是可能会有这样如下这样的需求,就是当点击某路由链接时,改变 document.title
      • 比如下面的图片所示,点击用户管理,标题就是显示用户管理

      	...
           { 
              path: 'users',
              component: Users,
              meta: { isAuth: true, title: '用户管理'  },
            },
           ...
      // 全局后置守卫
      router.afterEach(function (to, from) {
        document.title = to.meta.title || '管理系统'
      })
      

      注意:全局后置钩子是没有第三个参数中的 next 的

      七、路由独享守卫

      顾名思义是独有的路由守卫,与全局前置路由守卫没啥区别,只是作用的范围不同罢了,详细见代码:

      	...
           { 
              path: 'users',
              component: Users,
              meta: { isAuth: true, title: '用户管理'  },
              beforeEnter: (to, from, next)=>{
      		   // ...
              }
            },
           ...
      

      注意:独享路由守卫是没有后置路由守卫的

      八、组件内路由守卫

      写在组件内部的

      <template>
        <h4 class="text-center">订单管理</h4>
      </template>
      
      <script>
      export default {
        name: 'MyOrders',
        // 通过路由规则,进入该组件时被调用
        beforeRouteEnter(to, from, next){
          // ...
        },
        // 通过路由规则,离开该组件时被调用
        beforeRouteLeave(to, from, next){
          // ...
        }
      }
      </script>
      

      注意:是没有前置后置可分的,因为beforeRouteLeave是离开该组件时才会被调用,并不是跳转之后就调用的

      总结:

      ① 能够知道如何在 vue 中配置路由

      • createRouter、app.use(router)

      ② 能够知道如何使用嵌套路由

      • 通过 children 属性进行路由嵌套

      ③ 能够知道如何实现动态路由匹配

      • 使用冒号声明参数项、this.$route.params、props: true

      ④ 能够知道如何使用编程式导航

      • this.r o u t e r . p u s h 、 t h i s . router.push、this.router.push、this.router.go

      ⑤ 能够知道如何使用导航守卫

      • 路由实例.beforeEach((to, from, next) => { /* 必须调 next 函数 */ })

      ⑥ 能知道路由守卫有多少种

      • 全局前置路由守卫、全局后置钩子、独享路由守卫、组件内路由守卫

      ⑦能够知道路由的两种方式

      • hash 模式和 history 模式
        评论
        成就一亿技术人!
        拼手气红包6.0元
        还能输入1000个字符
         
        红包 添加红包
        表情包 插入表情
         条评论被折叠 查看
        添加红包

        请填写红包祝福语或标题

        红包个数最小为10个

        红包金额最低5元

        当前余额3.43前往充值 >
        需支付:10.00
        成就一亿技术人!
        领取后你会自动成为博主和红包主的粉丝 规则
        hope_wisdom
        发出的红包
        实付
        使用余额支付
        点击重新获取
        扫码支付
        钱包余额 0

        抵扣说明:

        1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
        2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

        余额充值