路由(route):就是根据特定的规则将数据包或请求从源地址传输到目标地址的过程。
在前端或者vue3项目中路由主要用于构建单页面应用程序(SPA),其中所有的页面都在同一个HTML文件中加载,通过JavaScript动态地切换显示不同的内容。
路由器(Router):路由器是负责管理路由的组件或模块。它定义了路由的规则、路径和对应的处理函数或组件。
请着重注意,路由器(Router)与路由(Route)的区别。路由器是用来管理路由的,你也可以理解为路由的集合。如果将一个一个的路由比作学生,那么路由器就是老师,负责管理所有的路由。在vue3项目中,路由是由路径和对应的组件构成的。我们通过切换不用的路径来展示不同的组件效果,路由器就是负责管理这些路径和路由对应的一些属性,来控制和管理路由的。
1、下载vue-router的依赖
npm install vue-router@4
2、在src目录下新建一个router目录,在router目录下新建一个index.ts文件,在这个ts文件中实现路由的定义的管理(这个文件起到的作用相当于路由器);我已经在components目录下新建了一些vue组件用来测试路由
import { createRouter, createWebHistory } from 'vue-router'
import LoginVue from '@/components/Login.vue'
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/',
name: 'login',
component: LoginVue
},
{
path: '/user',
name: 'user',
component: () => import('@/components/User.vue') // 懒加载
}
]
})
export default router
createRouter函数,新建一个路由器;
createWebHistory函数可以创建一个 HTML5 History 路由实例,从而能够支持浏览器的前进和后退按钮。
routes:存放一个一个的路由;在这里每一个路由都是一个对象,必须要指定的由两个参数:
path:指定路由的路径
component:指定路由对应的组件
也可以指定一些其他的属性,如name为路由命名、children设施嵌套路由等等,这些我们会在下面的内容中详细讲解;
3、在main.ts(或main.js)中引入路由
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中实现我们接下来的操作:
<script setup lang="ts">
import { RouterLink, RouterView } from 'vue-router'
</script>
<template>
<h1>App根组件</h1>
<RouterLink to="/login">login</RouterLink>
<hr>
<RouterLink to="/user">user</RouterLink>
<!-- 路由展示区 -->
<RouterView />
</template>
<style scoped>
</style>
RouterLink标签会被渲染成一个 <a>
标签,点击它时会触发路由切换。
RouterView 标签是展示区,会根据当前路由的路径自动加载对应的组件,并将其渲染到页面中。
响应效果:
RouterLink标签与a标签的不同在于使用RouterLink标签进行路由切换时不会刷新页面,而是用a标签进行路由切换时会自动刷新页面;
使用a标签进行切换也是直接写路由对应的路径即可
<a href="/login">login</a>
RouterLink标签的to属性时是一定要写的,原始的to属性只能写路由的路径。但是你可以在to属性前加一个:冒号,将:to属性变为响应式。这样就可以进行更多的操作了。
我们在进行路由的切换时也可以使用路由的名称进行切换;
<RouterLink :to="{name:'login'}">login</RouterLink>
使用RouterLink标签也能实现路由的跳转,但是这种跳转方式毕竟是写死的。我们只能通过点击相应的按钮来实行路由跳转,接下来我们通过js编程式的方式来实行路由的跳转,这也是我们在vue项目开发中常用到的路由跳转方式。
1、在App.vue组件中导入useRouter函数(注意是useRouter而不是useRoute。useRouter是路由器,useRoute是路由)
import {useRouter} from 'vue-router'
2、定义一个属性router来接收useRouter函数
const router=useRouter()
3、定义一个方法,并定义按钮触发,来实现路由的跳转;
const getLogin=()=>{
router.push({name:'login'})
}
路由的跳转有两种形式:
replace和push。区别在于,前者会替换当前的历史记录,而后者会添加新的历史记录。使用 replace 形式的导航,可以避免在浏览器历史记录中留下多个相同的页面。
使用replace形式实现路由的跳转与push形式的方法是一样的,只不过是改个名称罢了:
?
const getLogin=()=>{
router.replace({name:'login'})
}
通过点击导航时,视觉效果上“消失”了的路由组件,默认是被销毁掉的,需要的时候再去挂载。
有时候,一个路由的渲染效果是不能达到我们的预期效果的,这时候我们就需要进行路由之间的嵌套。
通过配置路由对象的 children
字段来定义子路由。
我又定义了三个组件:Login1.vue、Login2.vue、Login11.vue
要实现的效果是,Login1.vue、Login2.vue这两个路由组件是Login.vue的子组件、Login11.vue是Login1.vue的子组件;
直接在index.ts路由器定义路由的时候,同时定义这个路由的子路由(如果又子路由的话)
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/login',
name: 'login',
component: LoginVue,
children: [
{
path:'login1',
name:'login1',
component:()=>import('@/views/Login1.vue'),
children:[
{
path:'login11',
name:'login11',
component:()=>import('@/views/Login11.vue')
}
]
},
{
path:'login2',
name:'login2',
component:()=>import('@/views/Login2.vue')
}
]
},
{
path: '/user',
name: 'user',
component: () => import('@/components/User.vue') // 懒加载
}
]
})
可以看到我们直接在定义路由时,用children
属性就可以定义这个路由的子路由,并且children
是一个数组,这意味着我们可以定义多个子路由
注意,在子路由的 path
字段中,我们省略了斜杠 /
,而使用了相对路径 'login1'、‘login2’、‘login11’等
。这是因为在嵌套路由中,子路由的路径是相对于父级路由的。
虽然我们在路由器中定义了子路由,但是这个子路由默认是不会渲染的。接下来,我们需要确保在父级组件中添加 RouterView组件,以用于渲染子路由的内容。
父路由Login.vue:
?
<template>
<div>
<h2>login组件</h2>
<br>
<button @click="getLogin1">login1</button>
<button @click="getLogin2">login2</button>
<br>
<RouterView></RouterView>
</div>
</template>
<script lang="ts" setup>
import {useRouter,RouterView} from 'vue-router'
const router=useRouter()
const getLogin1=()=>{
router.push({name:'login1'})
}
const getLogin2=()=>{
router.push({name:'login2'})
}
</script>
<style scoped>
</style>
最终实现的效果:
路由的重定向:
使用 redirect
字段将指定的路径重定向到另一个路径。
path: '/login',
name: 'login',
component: LoginVue,
redirect: '/login/login2',
这表示,我访问/login路径时,会自动重定向到/login/login2路径。
路由的懒加载:
路由的懒加载是一种优化技术,它可以延迟加载路由组件,提高应用的性能。通过懒加载,只有在需要渲染该路由时才会下载和加载对应的组件代码。
这种是正常加载,它会一次性的把所有的组件全部加载进来
import LoginVue from '@/components/Login.vue'
component: LoginVue
这种是懒加载,只有在需要渲染该路由时才会下载和加载对应的组件代码。
component: ()=>import('@/components/Login.vue')
路由在进行跳转的时候可以进行参数的传递,你可以把要传递的参数给下一个路由来展示,这个功能是非常重要的我们在项目的开发中经常使用到这个特性;路由传参有两种方式;
可以直接使用query来进行参数的传递,这是route封装好的专门用来传参的属性,我们可以直接进行使用;
在App.vue中进行路由参数的传递:
const getLogin=()=>{
router.push({
name:'login',
query:{
name:'张三',
age:18
}
})
}
query是一个队象,你可以直接在这个对象中以键值对的形式传递参数;
在Login.vue中进行参数的接收:
使用useRoute来进行路由参数的接收;
?
import {useRouter,useRoute} from 'vue-router'
const route=useRoute()
console.log('接收传递的参数',route.query);
由于我们在进行传参时使用了路由的query参数,那么在接收参数时也要用query属性接收;
我们可以看一下控制台打印的效果:
可以看到我们已经接收到了由App.vue传递的参数了
使用params也可以进行参数的传递,与query参数不同的是,使用params进行路由传参时,必须要在路由路径上进行占位才行,并且在进行路由跳转时不能使用path路径跳转,只能使用命名路由的形式跳转;
路径占位:
path: '/login/:name/:age',
name: 'login',
component: ()=>import('@/components/Login.vue')
App.vue中进行路由传参:
?
const getLogin=()=>{
router.push({
name:'login',
params:{
name:'李四',
age:20
}
,
query:{
name:'张三',
age:18
}
})
}
在Login.vue中进行参数的接收:
import {useRouter,useRoute} from 'vue-router'
const route=useRoute()
console.log('接收传递的参数query===>',route.query);
console.log('接收传递的参数params===>',route.params);
我们可以看一下控制台打印的效果:
还有一点要注意,使用params进行传参时,不能传递对象和数组形式。这是params的特性;
并且你在路径上进行占位的参数,params也一定要进行传递,不然会报错的。
要想不报错,可以在占位时在参数后加一个?表示不是必要的参数
path: '/login/:name/:age?',
name: 'login',
component: ()=>import('@/components/Login.vue')
传递params参数时,必须使用name配置项,不能使用path,并且需要提前在规则中占位;
props
属性可以用于在路由组件中传递数据。
当使用 props
属性进行路由传参时,传递的数据会以 props 的形式传递给目标组件,这样目标组件就可以直接通过 props 来使用传递的数据。
props常见有两种写法:
1、将路由接收到的params参数直接发送给组件
path: '/login/:name/:age?',
name: 'login',
component: ()=>import('@/components/Login.vue'),
props: true
这种写法适用于params传参方式,使用了props
属性,就相当于在进行路由跳转时直接把参数在路由组件种进行传递;
相当于:
?
<Login name=李四 age=20/>
可以直接在目标路由中使用defineProps进行接收
let {name,age}=defineProps(['name','age'])
console.log(name,'==>',age);
2、函数式写法,可以自己决定将什么作为props给路由组件
path: '/login/:name/:age?',
name: 'login',
component: ()=>import('@/components/Login.vue'),
props(router){
return router.query
}
接收效果与第一种方式一样;