深入浅出Vue3之路由管理

274 阅读9分钟

路由

Vue 3 中的路由管理主要通过Vue Router 实现。Vue Router 是 Vue.js 的官方路由管理器,能够帮助你轻松地在 Vue 应用中实现路由功能,使得不同的 URL 可以显示不同的组件,从而提升用户体验。

1.Vue Router基础介绍

  1. 路由: 路由指的是 URL 到视图(组件)的映射关系。通过路由,可以根据不同的 URL 显示不同的组件。

  2. 单页面应用(SPA) : 在单页面应用中,所有的内容在一个页面中进行动态加载,用户不需要每次都刷新页面,从而提升了用户体验。Vue Router 使得在 SPA 中实现路由管理变得简单。

  3. 路由模式Vue Router 提供了两种主要的路由模式:

    • Hash模式:使用 URL 的 hash(#)部分来实现路由,URL 看起来像 http://example.com/#/home。优点是简单、兼容性好。
    • History模式:使用 HTML5 的 History API,可以实现更为美观的 URL,例如 http://example.com/home。需要后端支持配置,以确保所有请求都返回 index.html

2.Vue Router路由器的基础配置使用

2.1.路由器的配置

首先,要在 Vue 3 项目中使用Vue Router,需要安装它:

 npm install vue-router

通常在src源文件目录下,建立router文件夹以存储配置路由jsts文件,这里是一个示例:

 //创建一个路由器,并暴露出去
 ​
 //第一步:引入vue-router
 import {createRouter,createWebHistory} from "vue-router";
 ​
 //引入一个个可能呈现的组件
 import Home from "@/pages/Home.vue";
 import About from "@/pages/About.vue";
 import News from "@/pages/News.vue"
 ​
 //第二步:创建路由器
 const router = createRouter(
     {
         history:createWebHistory(),//路由器的工作模式
         routes:[
             {
                 path:"/Home",
                 component: Home
             },
             {
                 path:"/News",
                 component: News
             },
             {
                 path:"/About",
                 component: About
             },
         ]
     }
 )
 ​
 //第三步:暴露出去
 export default router
 ​

2.2.路由器的使用

我们仅仅是配置好了路由器后,我们需要在main.jsmain.ts中引入配置好的路由:

 import { createApp } from 'vue'
 import App from './App.vue'
 ​
 //引入路由器
 import router from "@/router";
 ​
 //创建一个应用
 const app = createApp(App)
 ​
 //使用路由器
 app.use(router)
 ​
 //挂载整个应用
 app.mount('#app')

在我们的app应用中引入路由器后,我们便可以在某个Vue组件中对应的地方使用路由器,包括执行怎样的操作,对应哪条路由

首先,引入vue-router依赖,它提供了调用路由器进行一些操作的接口:

  • <RouterLink>:提供了类似超链接<a>的链接路由的作用,它封装好了许多属性,如to实现对应哪条路由、active-class实现点击后添加类样式等
  • <RouterView>:便是提供将各条路由对应的组件挂载展示的标签
 import { RouterView, RouterLink } from "vue-router";

接着便可在模板标签中调用路由器,这里是一条示例:

 <template>
     <div class="app">
         <h2 class="title">Vue路由测试</h2>
         <!-- 导航区 -->
         <div class="navigate">
             <RouterLink to="/Home" active-class="active">首页</RouterLink>
             <RouterLink to="/News" active-class="active">新闻</RouterLink>
             <RouterLink :to="{ path: '/About' }" active-class="active">关于</RouterLink>
         </div>
         <!-- 展示区 -->
         <div class="main-content">
             <RouterView />
         </div>
     </div>
 </template>
 ​
 <script setup>
 import { RouterView, RouterLink } from "vue-router";
 </script>
 ​
 <style scoped>
 //...
 </style>

两个注意点

  • 路由组件通常存放在pagesviews文件夹,一般组件通常存放在components文件夹。
  • 通过点击导航,视觉效果上消失了的路由组件,默认是被卸载掉的,需要的时候再去挂载,

3.路由器的工作模式

3.1history模式

优点:URL更加美观,不带有#,更接近传统网站的URL

缺点:后期项目上线,需要服务端配合处理路径问题,否则刷新会有404错误(无法找到路径)

使用示例:

 import {createRouter,createWebHistory} from "vue-router";
 const router = createRouter({
     history:createWebHistory(),
     //......
 })

3.2hash模式

优点:兼容性更好,因为不需要服务器端处理路径

缺点:URL带有#不太美观,且在SE0优化方面相对较差

使用示例:

 import {createRouter,createHashHistory} from "vue-router";
 const router createRouter(
     history:createHashHistory(),//hash模式
     //.....
 )

4.to的两种写法

4.1.to的字符串写法

 <!-- 第一种:t0的字符串写法 -->
 <router-link active-class="active" to="/home">Home</router-link>

4.2.to的对象写法

 <! -- 第二种:t0的对象写法 -->
 <router-link active-class="active" to="{path:'/home'}">Home</router-link>

温馨提示

表面上看上去似乎第一种更简单,但在实际开发中,遇到需要给路由传入参数的情况,第二种写法才是最优解

5.路由的嵌套

在开发中我们会面临到这样一种情况:首页=>一级路由=>二级路由,相当于不断地在嵌套SPA,因此Vue3也提供了嵌套路由的技术

5.1.路由器中配置子路由

首先,在路由器中配置,一级路由对应的二级路由,这里也是提供了属性children用于存储配置的二级路由,当然二级路由对应的组件要先写好,这里是一个子路由配置示例:

 const router = createRouter(
     {
         history:createWebHistory(),
         routes:[
             {
                 path:"/Home",
                 component: Home
             },
             //在一级路由News中添加了二级路由details
             {
                 path:"/News",
                 component: News,
                 children:[
                     {
                         path:"detail",
                         component: Detail
                     }   
                 ]
             },
             {
                 path:"/About",
                 component: About
             },
         ]
     }
 )

温馨提示

  • 要先引入子路由对应组件
  • 二级路由的path属性不加'/'

5.2.子路由的使用

【2.2.路由器的使用】 介绍的类似,在一级路由中引入vue-router依赖后,创建相应位置所需的<RouterLink><RouterView>,便能实现路由的嵌套

温馨提示

子路由的路径添加在<RouterLink>中的to时,需要注意以"/一级路由/二级路由"的形式引用,否则若直接引用二级路由,将无法找到对应路由,什么都不会显示,下面是一个示例:

 <RouterLink to="/News/detail">xxx</RouterLink>

6.路由的传入参数

在开发工程中,我们常常需要向子路由中传入参数,以实现在一级路由组件中对不同元素的操作,来请求不同的子路由

以新闻这一主题为例,假设新闻组件对应一个一级路由,而这个新闻组件中,有许多不同新闻的标题,点击不同的标题能够显示标题对应的新闻内容,而新闻内容这部分便对应一个二级路由,那么再假设我们不使用传入参数这一形式,那么有多少个新闻标题我们便需要写多少个新闻内容的二级路由,这样相同的代码冗余过多,不利于维护,与Vue组件式开发的初衷相违背。

因此,在这个例子中,我们若能给新闻内容的二级路由传入新闻标题对应的唯一标识key值,便能通过这个key值实现对新闻内容组件的动态渲染,不仅减少了代码文件的冗余,而且在维护时,只需要更新修改新闻内容组件中的数据即可。

6.1路由的query参数

第一种写法:通过地址传入参数

首先,同样以新闻主题为例子,在新闻一级路由中的示例:

 <li v-for:="news in newsList" :key="news.id">
     <RouterLink :to="`/News/detail?id=${news.id}&title=${news.title}&content=${news.content}`">{{ news.title }}</RouterLink>
 </li>

这里通过v-bind指令和模板字符串的形式在路径后使用?传入参数,多个参数间使用&连接,传入给二级路由新闻的id,title,content数据。

接着,在二级路由中使用useRoute接受来自一级路由的数据,将数据赋给一个变量,下面是一个示例:

 import { useRoute } from "vue-router";
 let route = useRoute();
 console.log(route);

自此,一级路由的数据已成功传给二级路由,只需简单的在模板中调用即可,下面是一个示例:

 <template>
     <div>
         <ul class="class-list">
             <li>编号:{{ route.query.id }}</li>
             <li>标题:{{ route.query.title }}</li>
             <li>内容:{{ route.query.content }}</li>
         </ul>
     </div>
 </template>

温馨提示

这里的queryreactive类型响应式数据对象proxy的一个存储数据的属性

第二种写法:通过对象中query传入参数

参照 【4.2.to的对象写法】 ,加入query属性也可传入相应数据,下面是一个示例:

 <li v-for:="news in newsList" :key="news.id">
     <RouterLink :to="{
                         path: `/News/detail`,
                         query: {
                             id: news.id,
                             title: news.title,
                             content: news.content,
                         },
                     }">{{ news.title }}</RouterLink>
 </li>

6.2.路由的params参数

此方法是在URL上作文章的,不再过多赘述

首先在path中作出预置位,下面是一个示例:

 const routes = [
   {
     path: '/user/:id',
     component: UserProfile,
   },
   {
     path: '/search',
     component: SearchResults,
   },
 ];

接着,在<RouterLink>中传入参数,在路径后加入需要传入的数据即可,下面是一个示例:

 <template>
   <div id="app">
     <router-link to="/user/1">Go to User 1 Profile</router-link>
     <router-view></router-view>
   </div>
 </template>

备注1:传递params参数时,若使用to的对象写法,必须使用name配置项,不能用path。 备注2:传递params参数时,需要提前在规则中占位。

7.路由的props接受参数配置

上节介绍了传入参数的方法,但在接收参数过程中仍采用这种接收办法:

<template>
	<div>
		<ul class="class-list">
			<li>编号:{{ route.query.id }}</li>
			<li>标题:{{ route.query.title }}</li>
			<li>内容:{{ route.query.content }}</li>
		</ul>
	</div>
</template>

可见仍有过多的代码冗余,因此Vue3提供了在路由配置时props的使用办法:

 //props的对象写法,作用:把对象中的每一组key-value作为props传给Deta1l组件
 //props:{a:1,b:2,c:3},
 //props的布尔值写法,作用:把收到了每一组params参数,作为props传给Deta11组件
 //props:true
 //propsi的函数写法,作用:把返回的对象中每一组key-value作为props传给Deta1l组件
 props(route){
     console.log(route.query);
     return route.query
 },

在相应的路由组件中:

 import { defineProps } from "vue";
 defineProps(["id", "title", "content"]);

8.路由的replace历史记录属性

作用:控制路由跳转时操作浏览器历史记录的模式

浏览器历史记录有两种写入方式:分别为pushreplace

  • push:追加历史记录(默认值)
  • replace:替换当前记录

开启replace模式:

<RouterLink replace ....>News</RouterLink>

9.编程式路由导航

脱离<RouterLink>实现路由跳转 ,即不在模板元素中实现路由跳转,而是在脚本<script>中实现。

在模板元素中的路由跳转就是通过<RouterLink>,而它的本质实际上是对<a>的封装。通过对其属性的操作,能很容易实现路由的跳转,但是在面对复杂的需求时,这种方法便很不灵活。

例如一个简单的用户登录功能,需要根据用户输入信息在服务器数据库中检索才能实现路由的跳转,这便需要在脚本中先与服务器交互,再操作路由跳转。编程式导航应运而生。

<script>脚本中操作路由跳转的办法,下面是一个示例:

 import { useRouter } from "vue-router";
 //获取当前路由器对象
 const router = useRouter();
 //与模板元素交互的的接口函数
 function ShowDetails(News) {
     //对当前路由器对象push路由跳转的信息
     router.push({
         path: `/News/detail`,
         query: {
             id: News.id,
             title: News.title,
             content: News.content,
         },
     });
 }

示例中仅仅是与模板元素的交互接口,实际开发中还可以与例如计时器、与服务器交互等结合使用。

温馨提示

  • router.push()push()括号里的内容就是<RouterLink>to属性写的内容,具体可见 【4.to的两种写法】
  • 这里的push()是类似栈的追加历史记录的浏览器写入方式,也可以用replace()不保留历史记录写入

10.路由的重定向

让指定的路径重新定位到另一个路径 ,下面是一个在一级路由中的示例:

 {
     path:"/",
     redirect:"/Home"
 }