Vue组合式API--路由的使用详解

一、Vue路由的概述

vue-routerVue.js官方路由。它与Vue.js核心深度集成,让用Vue 构建单页应用(SPA)变得非常容易。

vue-router是基于路由和组件的。路由用于设定访问路径, 将路径和组件映射起来。

因此在vue-router的单页面应用中, 页面的路径的改变就是组件的切换。

前端路由通过URLhash做到URL和内容进行映射。

URLhash也就是锚点(#), 本质上是改变window.location的href属性。

hash的优势就是兼容性更好,在老版IE中都可以运行,但是缺陷是有一个#,显得不像一个真实的路径。

二、安装vue-router

npm install vue-router

三、vue-router路由的基本使用步骤

  • 创建路由需要映射的组件(打算显示的页面)

  • 通过createRouter创建路由对象,并且传入routeshistory的模式:

    • 配置路由映射: 组件和路径映射关系的routes数组;
    • 创建基于hash或者history的模式;
  • 使用app对象注册路由对象,使用use方法;

  • 路由使用: 通过<router-link><router-view>

    • <router-view>进行占位
    • <router-link>进行路由切换

3.1 准备路由需要显示的组件

Home.vue:

<template>
  <div class="about">
    这是Home组件
  </div>
</template>

<script setup>

</script>

About.vue

<template>
  <div class="about">
    这是About组件
  </div>
</template>

<script setup>

</script>

3.2 通过createRouter创建路由对象

router目录下的index.js中配置路由映射规则。

//1.1 引入创建路由的函数 以及采取的路由模式(hash还是history)
import { createRouter, createWebHashHistory} from 'vue-router'
//1.2 引入需要展示的组件
import Home from '../Views/Home.vue'
import About from '../Views/About.vue'

// 2 创建一个路由: 映射关系
const router = createRouter({
  // 2.1 指定采用的路由模式: hash
  history: createWebHashHistory(),
  // 2.2 配置路由映射关系
  routes: [
    { path: " /home", component: Home },
    { path: " /about", component: About }
  ]
})

export default router

historyhash两种方式最直观的区别就是浏览器地址栏上会不会带一个#号。

一般来讲都会选用hash作为路由模式。

3.3 使用app对象注册路由对象

main.js中拿到app对象,再使用app对象的use方法去注册路由对象。

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'	// 1.引入路由映射的js文件

const app = createApp(App)		// 2.拿到vue实例对象
app.use(router)					// 3.注册引入的路由映射
app.mount('#app')

3.4 使用路由

告知路由的页面的显示位置。

<template>
  <div class="app">
    <h2>App Content</h2>
   
    <div class="nav">
      <router-link to="/home" replace>首页</router-link>
      <!--
		写法二:
		<router-link :to="{ path: '/home' }" replace>首页</router-link> 
	  -->
      <router-link to="/about" replace active-class="active">关于</router-link>
    </div>
    <!-- router-view标签中就会显示当前路由对应的组件 -->
    <router-view></router-view>
  </div>
</template>

<script setup>
 

</script>
  • 使用router-link标签会在页面上渲染出两个a标签,跳转的路径就是to属性指向的组件
  • router-view标签会显示当前url下的对应组件

四、设置路由的默认路径

默认情况下, 进入网站的首页,需要渲染网站首页的内容。

这时需要在routes配置项下新增一个路由。

//1.1 引入创建路由的函数 以及采取的路由模式(hash还是history)
import { createRouter, createWebHashHistory} from 'vue-router'
//1.2 引入需要展示的组件
import Home from '../Views/Home.vue'
import About from '../Views/About.vue'

// 2 创建一个路由: 映射关系
const router = createRouter({
  // 2.1 指定采用的路由模式: hash
  history: createWebHashHistory(),
  // 2.2 配置路由映射关系
  routes: [
    { path: "/", redirect: "/home" },		//设置路由的默认路径
    { path: " /home", component: Home },
    { path: " /about", component: About }
  ]
})

export default router

五、router-link的其它属性

  • to属性: 是一个字符串,或者是一个对象

    • 字符串示例:to="/home"
    • 对象示例::to="{ path: '/home' }"
  • replace属性:

    • 设置replace属性的话,当点击时,会调用 router.replace(),而不是 router.push()
    • 直观的区别就是replace替换模式跳转的话,历史不会被记录,点击浏览器返回不会返回到上一个路由
  • active-class属性:

    • 设置激活a元素后应用的class,默认是router-link-active

      复写这个css类可以增加一些额外效果

      <style>
      
        .router-link-active {
          color: red;
          font-size: 20px;
        }
      
      </style>
      
    • 如果重命名的话例如设置了 replace active-class="active",那么久这么复写:

      <style>
      
        .active {
          color: red;
          font-size: 20px;
        }
      
      </style>
      
  • exact-active-class属性:

    • 链接精准激活时,应用于渲染的 的class,默认是router-link-exact-active
    • 主要用于路由嵌套中的精准匹配

六、路由懒加载

6.1 路由懒加载的作用

随着业务逻辑越来越多,今后打包构建应用时,JavaScript包会变得非常大,从而影响页面加载。

如果能把不同路由对应的组件分割成不同的代码块,当路由被访问的时候才加载对应组件,这样就会更加高效。

也可以提高首屏的渲染效率。

6.2 具体操作

import { createRouter, createWebHashHistory, createWebHistory } from 'vue-router'

// 创建一个路由: 映射关系
const router = createRouter({
  // 指定采用的模式: hash
  history: createWebHashHistory(),
  // 映射关系
  routes: [
    { 
      path: "/", 
      redirect: "/home" 
    },
    { 
      path: "/home", 
      component: () => import("../Views/Home.vue"),		//使用import函数导入组件
    },
    { 
      path: "/about", 
      component: () => import("../Views/About.vue"),
    },
  ]
})

export default router

component可以传入一个组件,也可以接收一个函数,该函数 需要放回一个Promise。

而import函数就是返回一个Promise,并且webpack会以import为分包节点,达到路由懒加载的目的。

七、路由的name和meta属性

  • name属性:记录路由独一无二的名称

  • meta属性:路由信息中自定义的数据,添加后在需要的时候可以拿到

import { createRouter, createWebHashHistory, createWebHistory } from 'vue-router'

// 创建一个路由: 映射关系
const router = createRouter({
  // 指定采用的模式: hash
  history: createWebHashHistory(),
  // 映射关系
  routes: [
    { 
      name: "home",
      path: "/home", 
      component: () => import("../Views/Home.vue"),
      meta: {
        name: "why",
        age: 18
      },
    }
  ]
})

export default router

八、动态路由

8.1 配置和使用动态路由

如果需要将给定匹配模式的路由映射到同一个组件,那么该如何做到呢?

例如,有一个 User 组件,它对所有用户进行渲染,但是用户的ID是不同的;

貌似使用/user/123user/456是没法跳转到同一个路由的。

Vue中的解决方案是,在Vue Router中,在路径中使用一个动态字段来实现,我们称之为 路径参数;

import { createRouter, createWebHashHistory } from 'vue-router'

// 创建一个路由: 映射关系
const router = createRouter({
  // 指定采用的模式: hash
  history: createWebHashHistory(),
  // 映射关系
  routes: [
    {
      path: "/user/:id",			//这里的:id就是一个路径参数
      component: () => import("../Views/User.vue")
    },
  ]
})

export default router

这样一来router-link中怎么给id的值都会显示User.vue组件

<router-link to="/user/123">用户123</router-link>
<router-link to="/user/321">用户456</router-link>

8.2 获取动态路由的参数值

如何在User.vue中获取到对应的参数值:

  • templat中,直接通过$route.params获取值;

    <template>
      <div class="user">
        <!-- 在模板中获取到id -->
        <h2>User: {{ $route.params.id }}</h2>
      </div>
    </template>
    
  • created中,通过this.$route.params获取值;

    <script>
      export default {
    	created(){
    	  console.log(this.$route.params.id)
    	},
      }
    </script>
    
  • setup中,我们要使用vue-router库给我们提供的一个hook,即 useRoute
    该Hook会返回一个Route对象,对象中保存着当前路由相关的值;

    <script setup>
      import { useRoute, onBeforeRouteUpdate } from 'vue-router'
    
      // 第一次的时候执行这个函数获取路由参数
      const route = useRoute()
      console.log(route.params.id)
    
      // 获取route跳转id,即在  /user/123跳转到/user/456时会触发下面的函数,获取到起点和终点的参数
      // 这个方式用的很少,基本不会有这种需求,了解即可 
      onBeforeRouteUpdate((to, from) => {
        console.log("from:", from.params.id)
        console.log("to:", to.params.id)
      })
    
    </script>
    

九、关于没有匹配到的路由路径的处理

可以编写一个NotFound.vue这个组件,并配置路由规则,如果路由不匹配则显示这个组件。

NotFound.vue

<template>
  <div class="not-found">      
    <!-- 可以通过 $route.params.pathMatch获取到传入的参数 -->
    <h2>NotFound: 您当前的路径{{ $route.params.pathMatch }}不正确, 请输入正确的路径!</h2>
  </div>
</template>

<script setup>
</script>

<style scoped>
  .not-found {
    color: red;
  }
</style>

router目录下的index.js

import { createRouter, createWebHashHistory } from 'vue-router'

// 创建一个路由: 映射关系
const router = createRouter({
  // 指定采用的模式: hash
  history: createWebHashHistory(),
  // 映射关系
  routes: [
    {
      path: "/:pathMatch(.*)*",
      component: () => import("../Views/NotFound.vue")
    }
  ]
})

export default router

/:pathMatch(.*)/:pathMatch(.*)*的区别:

  • 使用/:pathMatch(.*)语法时,获取到的参数为/user/123
  • 使用/:pathMatch(.*)*语法时,获取到的参数为["user","123"]

十、路由嵌套

如果Home页面本身也存在多个组件之间来回切换,这时候就可以使用路由嵌套。

只需要配置children属性即可。

10.1 路由嵌套基本配置

import { createRouter, createWebHashHistory, createWebHistory } from 'vue-router'

// 创建一个路由: 映射关系
const router = createRouter({
  // 指定采用的模式: hash
  history: createWebHashHistory(),
  // 映射关系
  routes: [
    { 
      path: "/", 
      redirect: "/home" 				    //配置一级路由的默认首页
    },
    { 
      name: "home",
      path: "/home", 
      component: () => import("../Views/Home.vue"),
      meta: {
        name: "张三",
        age: 18
      },
      children: [
        {
          path: "/home",
          redirect: "/home/recommend"		//配置二级路由的默认首页
        },
        {
          path: "recommend", 
          component: () => import("../Views/HomeRecommend.vue")
        },
        {
          path: "ranking", // /home/ranking
          component: () => import("../Views/HomeRanking.vue")
        }
      ]
    },
  ]
})


export default router

10.2 路由嵌套动态配置

import { createRouter, createWebHashHistory, createWebHistory } from 'vue-router'

// 创建一个路由: 映射关系
const router = createRouter({
  // 指定采用的模式: hash
  history: createWebHashHistory(),
  // 映射关系
  routes: [
    { 
      path: "/", 
      redirect: "/home" 				    //配置一级路由的默认首页
    },
    { 
      name: "home",
      path: "/home", 
      component: () => import("../Views/Home.vue"),
    },
  ]
})

// 如果是vip的话 就动态添加一个home下的二级路由
// 这个home是上面routes中配置的name属性
let isVip = true
if (isVip) {
    router.addRoute("home", {
        path: "vip",
        component: () => import("../Views/HomeVip.vue")
    })
}


export default router

十一、删除路由

  • 添加一个name相同的路由

    • 因为name属性时唯一的,后面添加的相同name的路由会覆盖之前的
    router.addRoute({ path: '/about' , name: 'about' , component: About })
    
  • 通过removeRoute方法,传入路由的名称

    router.removeRoute( ' about')
    
  • 通过addRoute方法的返回值回调

    const removeRoute = router.addRoute({ path:'/about', name:'about', component:About })
    removeRoute()
    

十二、路由的其他方法

  • router.hasRoute():检查路由是否存在。
  • router.getRoutes():获取一个包含所有路由记录的数组。

十三、路由守卫

vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航

13.1 全局的前置守卫beforeEach参数和返回值说明

  • 它的两个参数:

    • to:即将进入的路由Route对象;
    • from:即将离开的路由Route对象;
  • 它的返回值:

    • false:取消当前导航;
    • 不返回或者undefined:进行默认导航;
    • 返回一个路由地址:
      • 可以是一个string类型的路径;
      • 可以是一个对象,对象中包含pathqueryparams等信息;
  • 可选的第三个参数:next(不推荐使用)

    • Vue2中是通过next函数来决定如何进行跳转的;
    • Vue3中是通过返回值来控制的,不再推荐使用next函数,这是因为开发中很容易调用多次next

13.2 beforeEach的使用场景之一:登录守卫

// 进行任何的路由跳转之前, 传入的beforeEach中的函数都会被回调
// 需求: 进入到订单(order)页面时, 判断用户是否登录(isLogin -> localStorage保存token)
// 情况一: 用户没有登录, 那么跳转到登录页面, 进行登录的操作
// 情况二: 用户已经登录, 那么直接进入到订单页面
router.beforeEach((to, from) => {
  // 进入到订单页面时, 判断用户是否登录
  const token = localStorage.getItem("token")
  if (to.path === "/order" && !token) {
    return "/login"
  }
})

13.3 路由守卫官方文档

https://router.vuejs.org/zh/guide/advanced/navigation-guards.html

13.4 完整的路由导航解析流程

  • 导航被触发。

  • 在失活的组件里调用 beforeRouteLeave 守卫。

  • 调用全局的beforeEach守卫。

  • 在重用的组件里调用beforeRouteUpdate 守卫(2.2+)。

  • 在路由配置里调用 beforeEnter

  • 解析异步路由组件。

  • 在被激活的组件里调用 beforeRouteEnter

  • 调用全局的 beforeResolve 守卫(2.5+)。

  • 导航被确认。

  • 调用全局的 afterEach 钩子。

  • 触发 DOM 更新。

  • 调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。

十四、编程式路由跳转

12.1 基本使用

有时候希望通过代码来完成页面的跳转,比如点击的是一个按钮时就进行页面跳转。

  • 使用OptionsAPI

    this.$router.push( '/profile')
    //或者
    this.$router.push({
    	path: '/profile'
    })
    

    可以传入字符串或者对象。

  • 使用setup语法糖加上CompositionAPI

    <template>
      <div class="app">
        <div class="nav">
          <span @click="homeSpanClick">首页</span>
          <button @click="aboutBtnClick">关于</button>
        </div>
        <router-view></router-view>
      </div>
    </template>
    
    <script setup>
      import { useRouter } from 'vue-router'
    
      const router = useRouter()
    
      // 监听元素的点击
      function homeSpanClick() {
        // 跳转到首页
        // router.push("/home")		// 没有别的参数可以使用传递字符串的简写方式
        router.push({
          path: "/home"				// name: "home" 使用name方式也可以,不过不推荐
        })
      }
      function aboutBtnClick() {
        // 跳转到关于
        router.push({
          path: "/about"
        })
      }
    
    </script>
    

12.2 使用query来传递参数

1)设置参数

<template>
  <div class="app">
    <div class="nav">
      <button @click="aboutBtnClick">关于</button>
    </div>
    <router-view></router-view>
  </div>
</template>

<script setup>
  import { useRouter } from 'vue-router'

  const router = useRouter()

  function aboutBtnClick() {
    // 跳转到关于
    router.push({
      path: "/about",
      query: {name: "why",age: 18}
    })
  }
</script>

2)在About.vue中获取参数

<template>
  <div class="about">
    <h2>About: {{ $route.query }}</h2>
  </div>
</template>

12.3 编程式路由跳转时push和replace的如别

使用push的特点是压入一个新的页面,那么在用户点击返回时,上一个页面还可以回退。

但是如果我们希望当前页面是一个替换 操作,那么可以使用replace,使用replace的话,上个页面无法回退。

12.4 编程式路由控制页面前进或者后退的方式

  • routergo方法:
<template>
  <div class="about">
    <button @click="backBtnClick">返回</button>
  </div>
</template>

<script setup>
  import { useRouter } from 'vue-router'

  const router = useRouter()

  function backBtnClick() {
    //·向前移动一条记录,与·router.forward()·相同
    router.go(1)
    //·返回一条记录,与router.back()·相同
    router.go(-1)
    //·前进·3·条记录
    router.go(3)
    //·如果没有那么多记录,静默失败
    router.go(-100)
    router.go (100)
  }

</script>
  • routerback方法:

通过调用 history.back() 回溯历史,相当于 router.go(-1),和浏览器左上角的←效果一样

<template>
  <div class="about">
    <button @click="backBtnClick">返回</button>
  </div>
</template>

<script setup>
  import { useRouter } from 'vue-router'

  const router = useRouter()

  function backBtnClick() {
    router.back()
  }

</script>
  • routerforward方法:

通过调用 history.forward()在历史中前进,相当于router.go(1),和浏览器左上角的→效果一样

<template>
  <div class="about">
    <button @click="backBtnClick">返回</button>
  </div>
</template>

<script setup>
  import { useRouter } from 'vue-router'

  const router = useRouter()

  function backBtnClick() {
    router.forward()
  }

</script>
  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值