Vue3简单快速基础入门 (四)
Vue3简单快速基础入门 (四)
Vue Router 快速掌握
1. Vue Router
Vue Router 是 Vue 官方的客户端路由解决方案。
客户端路由的作用是在单页应用 (SPA) 中将浏览器的 URL 和用户看到的内容绑定起来。当用户在应用中浏览不同页面时,URL 会随之更新,但页面不需要从服务器重新加载。
Vue Router 基于 Vue 的组件系统构建,你可以通过配置路由来告诉 Vue Router 为每个 URL 路径显示哪些组件。
Vue-Router官方网址
1.1 安装
新建一个Vue项目,创建
views文件夹,并创建显示页面(自定义即可,方便路由显示),在项目目录终端下输入命令,安装Vue Router:
npm install vue-router@4
安装完成后,
package.json文件中会自动添加vue-router依赖。这里版本为"vue-router": "^4.5.0"
1.2 配置使用
首先创建
router文件夹,在router文件夹下新建一个index.js文件,内容如下:
// 导入createRouter和createWebHistory方法
// createRouter用于创建路由实例,createWebHistory用于使用HTML5 History API进行路由管理
import { createRouter, createWebHistory } from 'vue-router'
// 设置路由规则
// routes是一个数组,包含多个路由对象,每个对象定义了一个路由的路径和对应的组件
const routes = [
{
// 访问路由路径为根路径 '/'
path: '/',
// 对应组件为懒加载的index.vue组件
// 懒加载:只有在组件被访问时才会加载该组件,有助于提高应用的初始加载速度
component: () => import('../views/index.vue')
},
{
// 访问路由路径为'/content'
path: '/content',
// 对应组件为懒加载的content.vue组件
component: () => import('../views/content.vue')
}
]
// 创建路由实例
// 通过createRouter方法创建router实例,并传入配置对象
const router = createRouter({
// 使用createWebHistory方法创建一个history模式的导航实例
// history模式:利用HTML5 History API使得URL看起来像标准的网站URL
history: createWebHistory(),
// 将之前定义好的路由规则数组传入
routes
})
// 将router实例导出
export default router
在
main.js文件中导入router实例,并挂载到Vue实例上:
import { createApp } from 'vue'
import App from './App.vue'
import router from '../router/index.js'
// 将router实例注册到Vue实例上
createApp(App).use(router).mount('#app')
最后,在
App.vue文件中使用<router-view>组件来渲染路由匹配到的组件:
<script setup>
</script>
<template>
<!-- 根据路由规则,渲染对应的组件 -->
<router-view />
</template>
<style scoped>
</style>
注意:在 Vue Router 中,history 选项支持三种不同的模式,分别是 createWebHistory、createWebHashHistory 和 createMemoryHistory,下面详细介绍它们的特点和作用:
createWebHistory:传统模式,在这种模式下,URL 看起来就像标准的网站 URL,没有 # 符号,更符合用户对传统网站 URL 的认知,提升了 URL 的可读性和美观度。createWebHashHistory:哈希模式,该模式使用 URL 中的哈希值(#)来实现路由导航。当 URL 中的哈希值发生变化时,浏览器不会向服务器发送新的请求,而是触发 Vue Router 的路由变化,从而实现单页面应用的导航。createMemoryHistory:内存模式,该模式将路由的历史记录保存在内存中,不与浏览器的历史记录进行交互。这种模式通常用于非浏览器环境,如 Node.js 服务器端渲染(SSR)、测试环境等。
2. 配置路径别名@和VSCode路径提示
在
router/index.js文件中,我们使用了import '../views/index.vue'来导入index.vue组件,但是经常会看到别的vue项目中,使用的是@,也就是路径别名。
接下来,我们通过配置,从而使用@
2.1 配置路径别名
配置路径别名,在
vite.config.js文件中,代码如下:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// 引入 path 模块
import path from 'path'
export default defineConfig({
plugins: [vue()],
// 解析配置,主要用于设置路径别名等
resolve: {
// 别名配置对象,允许我们使用简化的路径来引用文件
alias: {
// `path.resolve(__dirname, './src')` 是 Node.js 的 `path` 模块中的方法
// `__dirname` 表示当前文件所在的目录,`path.resolve` 会将其和 `./src` 拼接成一个绝对路径
// 设置路径别名 '@' 指向 '/src' 目录,这样在引入文件时可以使用 '@' 来代替 '/src'
'@': path.resolve(__dirname, './src')
}
}
})
接着就可以使用
@去导入组件了,比如在router/index.js文件中,我们可以这样写:
const routes = [
{
// 访问路由路径为根路径 '/'
path: '/',
// 对应组件为懒加载的index.vue组件
// 懒加载:只有在组件被访问时才会加载该组件,有助于提高应用的初始加载速度
component: () => import('@/views/index.vue')
},
{
// 访问路由路径为'/content'
path: '/content',
// 对应组件为懒加载的content.vue组件
component: () => import('@/views/content.vue')
}
]
接下来终端输入
npm run dev启动项目,访问对应路由路径,可以看到正常访问。
2.2 VSCode路径提示
上面使用了路径别名
@来替换原来的路径方式,但是发现在VSCode中,使用@方式,并没有路径提示,所以接下来就对路径提示进行配置。
因为创建vue项目时,选择的语言为js,所以创建文件
jsconfig.json文件,内容如下:
{
"compilerOptions":{
"baseUrl": ".",
"paths": {
"@/*": ["src/*"] // 配置 @ 符号指向 src 目录及其子目录
}
}
}
这样,VSCode中,使用
@符号,就会有路径提示功能。
3. 使用查询字符串或路径传递参数
在Vue Router中,可以通过
query属性来传递查询字符串参数,通过params属性来传递路径参数。
3.1 传递查询字符串参数
查询字符串,也就是路径上的
?后面的参数,可以通过query属性来传递。例如:http://localhost:5173/content?id=100&name=十一月
然后,可以在content路由对应的组件content.vue中,通过$route.query来获取查询字符串参数:
<script setup>
</script>
<template>
<h1>这里是内容页-content.vue</h1>
<h1>id: {{ $route.query.id }}</h1>
<h1>name: {{ $route.query.name }}</h1>
</template>
<style>
</style>
注意:$route是一个全局属性,所以不需要引入,直接使用即可。
3.2 传递路径参数
传递路径参数,也就是路径中的参数,可以通过
params属性来传递。例如:http://localhost:5173/content/100/name/十一月
需要先修改路由规则,确保路由规则和路径参数匹配,在router/index.js中修改:
//...
const routes = [
{
// 修改路由规则,设置路径参数
path: '/content/:id/name/:name',
component: () => import('@/views/content.vue')
}
]
//...
然后,可以在content路由对应的组件content.vue中,通过
$route.params来获取路径参数:
但是路径参数有一个问题,就是参数必须和路径规则匹配,如果我们不传id或name,那么就会提示没有匹配的路由,但有些时候,参数是可选的,我们希望可以不传参数,那么怎么办呢?
其实也很简单,在路由参数后使用?即可,表示该路由参数可选:
//...
const routes = [
{
// 修改路由规则,设置路径参数 并且 name 参数可选
path: '/content/:id/name/:name?',
component: () => import('@/views/content.vue')
}
]
//...
4. 定义别名、router-link 组件、路由名称、编程式导航
在
router/index.js文件中,我们定义了路由规则,规则中,使用了path去指定了路由路径,component属性来指定了路由对应的组件。
4.1 定义别名
接下来,学习使用
alies去指定路由别名,可以允许有多个别名。通过访问别名,也能够正常去访问对应的组件。
//...
const routes = [
{
path: '/',
// 设置别名为/index
// alias: '/index',
// 设置多个别名 使用数组
alias:["/index","/home"],
component: () => import('@/views/index.vue')
}
]
// ...
4.2 router-link 组件
router-link组件是 Vue Router 提供的组件,可以用来创建路由链接。它可以绑定到路由的路径,当点击时,会导航到对应的路由。其实也就是相当于一个a标签,但是可以绑定路由。
<!-- index.vue中编写 -->
<script setup>
</script>
<template>
<h1>这里是首页-index.vue</h1>
<router-link to="/content/100/name/十一月">Router-Link路径传递参数</router-link>
<br>
<router-link to="/user?id=200&url=https://blog.xy21lin.cn">Router-Link传递查询参数</router-link>
</template>
<style>
</style>
4.3 路由名称
在
index.js文件定义的路由规则中,添加name属性,可以给路由规则定义一个名称,以此来解决动态绑定router-link路径传递参数并方便后续编程式导航。
const routes = [
{
path: '/content/:id/name/:name',
// 设置路由名称,解决动态绑定router-link路径传递参数 路由不匹配问题
name: 'content',
component: () => import('@/views/content.vue')
},
{
path:'/user',
component: () => import('@/views/user.vue')
}
]
<script setup>
</script>
<template>
<h1>这里是首页-index.vue</h1>
<!-- 这样子动态绑定传递,发现没有匹配的content路由,是因为index.js中,设置的路由规则是完全匹配了参数的,所以需要定义路由名称,也就是去设置一个name属性 -->
<!-- <router-link :to="{path:'/content',params:{id:100,name:'十一月'}}">Router-Link路径传递参数-动态绑定</router-link> -->
<router-link :to="{name:'content',params:{id:100,name:'十一月'}}">Router-Link路径传递参数-动态绑定</router-link>
<br>
<router-link :to="{path:'/user',query:{id:200,url:'https://blog.xy21lin.cn'}}">Router-Link传递查询参数-动态绑定</router-link>
</template>
<style>
</style>
4.4 编程式导航
编程式导航,就是通过代码来控制路由的跳转,而不是通过浏览器的前进、后退按钮。通过
router.push()方法可以实现编程式导航。
<script setup>
import {useRouter} from 'vue-router'
const router = useRouter()
let id = 888
let name = "编程式导航"
let url = "https://blog.xy21lin.cn"
//定义跳转方法
const gotoContent = ()=>{
// router.push("/content/999/name/编程式导航")
router.push({name:"content",params:{id:id,name:name}})
}
const gotoUser = () =>{
// router.push("/user?id=200&url=https://blog.xy21lin.cn")
router.push({path:"/user",query:{id:id,url:url}})
}
</script>
<template>
<h1>这里是首页-index.vue</h1>
<router-link to="/content/100/name/十一月">Router-Link路径传递参数</router-link>
<br>
<router-link to="/user?id=200&url=https://blog.xy21lin.cn">Router-Link传递查询参数</router-link>
<hr>
<!-- 这样子动态绑定传递,发现没有匹配的content路由,是因为index.js中,设置的路由规则是完全匹配了参数的,所以需要定义路由名称,也就是去设置一个name属性 -->
<!-- <router-link :to="{path:'/content',params:{id:100,name:'十一月'}}">Router-Link路径传递参数-动态绑定</router-link> -->
<router-link :to="{name:'content',params:{id:100,name:'十一月'}}">Router-Link路径传递参数-动态绑定</router-link>
<br>
<router-link :to="{path:'/user',query:{id:200,url:'https://blog.xy21lin.cn'}}">Router-Link传递查询参数-动态绑定</router-link>
<hr>
<button @click="gotoContent()">跳转到内容页</button>
<button @click="gotoUser()">跳转到用户页</button>
</template>
<style>
</style>
5. 嵌套路由结合共享组件
嵌套路由,就是在一个路由下,再定义子路由,这样子,就可以实现多级路由。例如定义了一个路由vip,再在vip下定义order,此时order路由也就是
/vip/order。
共享组件,就是在多个路由下,共用一个组件,这样子,就可以实现组件的复用。
接下来,我们来实现嵌套路由和共享组件。首先创建一个
vip.vue,以及vip文件夹,并在内创建order.vue、info.vue、default.vue三个组件。以及在components文件夹下创建header.vue和footer.vue两个组件,作为公共组件。
<!-- header.vue -->
<script setup>
</script>
<template>
<h1>这里是Header-header.vue</h1>
</template>
<style>
</style>
<!-- footer.vue -->
<script setup>
</script>
<template>
<h1>这里是Footer-footer.vue</h1>
</template>
<style>
</style>
<!-- default.vue -->
<script setup>
</script>
<template>
<h1>这里是会员默认页</h1>
</template>
<style>
</style>
<!-- order.vue -->
<script setup>
</script>
<template>
<h1>这里是会员订单页</h1>
</template>
<style>
</style>
<!-- info.vue -->
<script setup>
</script>
<template>
<h1>这里是会员信息页</h1>
</template>
<style>
</style>
<!-- vip.vue -->
<script setup>
import Header from '@/components/header.vue'
import Footer from '@/components/footer.vue'
</script>
<template>
<!-- 使用公共组件Header和Footer -->
<Header />
<!-- 渲染子路由,不渲染就无法显示子路由页面内容 -->
<router-view />
<Footer />
</template>
<style>
</style>
然后在
router/index.js文件中,定义vip路由,并在children属性中定义子路由:
//...
const routes = [
{
// 访问路由路径为根路径 '/'
path: '/',
// alias: '/index',
alias:["/index","/home"],
component: () => import('@/views/index.vue')
},
{
path: '/content/:id/name/:name',
name: 'content',
component: () => import('@/views/content.vue')
},
{
path:'/user',
component: () => import('@/views/user.vue')
},
{
path:"/vip",
component: () => import('@/views/vip.vue'),
// 定义子路由
children:[
{
path:'', // http://localhost:5173/vip
component: () => import('@/views/vip/default.vue')
},
{
path:'order', // http://localhost:5173/vip/order
component: () => import('@/views/vip/order.vue')
},
{
path:'info', // http://localhost:5173/vip/info
component: () => import('@/views/vip/info.vue')
}
]
}
]
//...
6. 重定向
重定向,就是当访问一个路由时,根据设定的重定向规则,就自动跳转到另一个路由。
例如,我们定义了一个路由/svip,但是我们希望用户访问/svip时,自动重定向跳转到/vip
const routes = [
{
// 访问路由路径为根路径 '/'
path: '/',
alias:["/index","/home"],
component: () => import('@/views/index.vue')
},
{
path: '/content/:id/name/:name',
name: 'content',
component: () => import('@/views/content.vue')
},
{
path:'/user',
component: () => import('@/views/user.vue')
},
{
path:"/vip",
component: () => import('@/views/vip.vue'),
// 定义子路由
children:[
{
path:'',
component: () => import('@/views/vip/default.vue')
},
{
path:'order',
component: () => import('@/views/vip/order.vue')
},
{
path:'info',
component: () => import('@/views/vip/info.vue')
}
]
},
{
path:'/svip',
// 实现重定向
redirect:'/vip'
}
]
当访问
/svip时,会自动跳转到/vip,接下来试一试,可不可以实现编程式导航一样传递到项目
const routes = [
{
// 访问路由路径为根路径 '/'
path: '/',
alias:["/index","/home"],
component: () => import('@/views/index.vue')
},
{
path: '/content/:id/name/:name',
name: 'content',
component: () => import('@/views/content.vue')
},
{
path:'/user',
component: () => import('@/views/user.vue')
},
{
path:"/vip",
component: () => import('@/views/vip.vue'),
// 定义子路由
children:[
{
path:'',
component: () => import('@/views/vip/default.vue')
},
{
path:'order',
component: () => import('@/views/vip/order.vue')
},
{
path:'info',
component: () => import('@/views/vip/info.vue')
}
]
},
{
path:'/svip',
// 实现重定向
// redirect:'/vip'
// 要实现编程式导航一样传递到项目 也就是类似这样子 router.push({name:"content",params:{id:id,name:name}})
redirect: {name:"content",params:{id:99,name:"十一月"}}
}
]
再次访问
/svip时,会自动跳转到/content/99/name/十一月,并显示内容页。说明是可以正常进行重定向的。
7. 全局前置守卫
全局前置守卫,就是在所有路由跳转前,都会执行一段代码,比如检查是否登录,是否有权限等。
我们在main.js文件中,定义全局前置守卫:
import { createApp } from 'vue'
import App from './App.vue'
import router from './router/index.js'
// 配置路由前置守卫
router.beforeEach((to, from, next) => {
// to 即将进入的路径信息
// from 即将离开的路径信息
console.log(to)
console.log(from)
if(to.name == "content"){
// 如果跳转路由名称为 content 就进行拦截
// next(false)
// 如果跳转路由名称为 content 就进行重定向到vip
next('/vip')
}else{
next()
}
})
// 将router实例注册到Vue实例上
createApp(App).use(router).mount('#app')
在前置守卫中,对路由名称
content的路由进行了拦截,这样子就不会进行跳转,在实际项目中,需要根据实际情况进行拦截、重定向等操作,可以根据实际情况进行操作。
注意:除了全局前置守卫外,还有全局解析守卫、全局后置钩子等,前置守卫最多,剩余内容可以自行查阅官方文档。