# Vue Router 路由传参、别名、匹配语法、编程式导航
TIP
从本节内容开始我们正式学习 Vue Router 核心基础 和 在实际开发中的实践应用相关内容
- Vue Router 的基本用法
- Vue Router 路由传参
- 路由别名
- 命名视图
- 动态路由的匹配语法
- Vue Router 编程式导航
- 实战应用:项目框架搭建
# 一、Vue Router 的基本用法
TIP
Vue Router 是 Vue.js (opens new window) 的官方路由。它与 Vue.js 核心深度集成,让用 Vue.js 构建SPA 单页应用变得轻而易举。在 Vue3 中需要安装vue-router
4 版本。
Vue Router 官网地址:https://router.vuejs.org/zh/guide/ (opens new window)
# 1、使用 vue-router 的步骤
TIP
在 vue3 中使用vue-router@4.x
版本步骤
- 第一步:安装
vue-router@4
- 第二步:定义路由组件
- 第二步:创建路由实例
- 第三步:配置路由映射:路径和组件映射关系
- 第四步:在 app 应用实例中挂载创建的路由实例
- 第五步:使用路由:通过
<router-link>
和<router-view>
组件
接下来,我们按以上步骤,最终实现如下效果的单页面应用
# 1.1、第一步:安装vue-router@4.x
版本
TIP
执行以下 npm 命令,安装vue-router
4.x 版本,安装成生产依赖
npm install vue-router@4
# 1.2、第二步:定义路由组件
TIP
在 src/views/
目录下新建当前应用需要用到的所有路由组件(也称视图组件)
views / Home.vue; // Home 组件
views / About.vue; // About 组件
views / News.vue; // News 组件
# 1.3、第三步:创建路由实例
TIP
在src/router/
目录下新建router.js
文件,此文件最终对外暴露router
路由实例
import { createRouter, createWebHashHistory } from "vue-router";
// createRouter方法,用来创建路由实例,参数为一个对象,用来配置路由相关信息
const router = createRouter({
// 路由模式,createWebHashHistory()创建 hash 模式。
history: createWebHashHistory(),
});
// 对外暴露router实例
export { router };
# 1.4、第四步:配置路由映射 - 路径和组件映射关系
TIP
- ①、导入路由组件
- ②、定义路由:路径与组件的映射关系
- ③、在
createRouter
方法的参数中配置routes
选项
import { createRouter, createWebHashHistory } from "vue-router";
// 1、导入路由组件 -------------------
import Home from "../views/Home.vue";
import About from "../views/About.vue";
import News from "../views/News.vue";
// 2、定义一些路由: 路径和组件映射关系 -------------------
const routes = [
{
path: "/", // 路径
component: Home, // 路径对应渲染的组件
},
{
path: "/about",
component: About,
},
{
path: "/news",
component: News,
},
];
// createRouter方法,用来创建路由实例,参数为一个对象,用来配置路由相关信息
const router = createRouter({
// 路由模式,createWebHashHistory()创建 hash 模式。
history: createWebHashHistory(),
// 3、配置routes -------------------
routes, // 'routes':routes的缩写
});
// 对外暴露router实例
export { router };
# 1.5、第五步:全局注册 router 实例
TIP
在main.js
中利用 app.use 方法注册 router 路由实例
import { createApp } from "vue";
import App from "./App.vue";
// 导入router实例
import { router } from "./router/router.js";
const app = createApp(App);
// 全局注册路由
app.use(router);
app.mount("#app");
# 1.6、第六步:使用路由通过<router-link>
和<router-view>
TIP
可以在App.vue
组件中调用<router-link>
和<router-view>
组件使用路由
<router-link>
组件用来创建链接,最终会生成<a>
标签形式的导航<router-view>
组件用来显示与 Url 对应的组件内容
<!--App组件-->
<template>
<ul class="router-link">
<!--创建a标签链接 to属性最终转换为a标签的href属性值-->
<li><router-link to="/">网站首页</router-link></li>
<li><router-link to="/about">关于我们</router-link></li>
<li><router-link to="/news">新闻中心</router-link></li>
</ul>
<div class="router-view">
<!--url对应组件内容渲染出口-->
<router-view></router-view>
</div>
</template>
<style>
.router-link {
display: flex;
justify-content: center;
text-align: center;
list-style: none;
margin-top: 30px;
}
.router-link li {
margin: 0 10px;
}
.router-link li a {
color: #000;
font-size: 16px;
text-decoration: none;
}
.router-link li a:hover {
color: tomato;
}
.router-view {
width: 80%;
margin: 30px auto;
font-size: 20px;
min-height: 300px;
background-color: rgb(251, 249, 249);
}
</style>
经过以上 6 步,最终我们完成了刚开始我们期望的效果。
# 2、路由模式
TIP
createRouter
方法参数对象的history
属性用来指定路由的模式,当history
的值为
createWebHashHistory()
创建 hash 路由模式createWebHistory()
创建 history 路由 模式
const router = createRouter({
// history属性指定路由模式
history: createWebHashHistory(), // 创建 hash 路由 模式。
// history: createWebHistory(), // 创建 history 路由 模式
});
# 3、链接激活时 Class 类名
TIP
默认情况下,链接被激活时会加上router-link-active
Class 类名,比如前面提到的案例
我们可以通过添中router-link-active
Class 类名,来控制被激活链接的样式
/* 在上面案例的基础上,在style标签中 添加如下css样式 */
.router-link li a.router-link-active {
color: tomato;
}
添加以上 css 后,最终渲染效果如下
我们还可以设置<router-link>
组件的active-class
属性值来更改链接激活时使用的 CSS 类名
/* 我们修改上面案例中的如下css样式 */
.router-link li a.router-link-active {
color: tomato;
}
/* 修改成 */
.router-link li a.active {
color: tomato;
}
以上代码,最终渲染后效果如下:
关于什么情况下会加上的
router-link-exact-active
Class 类名,及有什么用,后面会讲到
# 4、去掉路由历史记录
TIP
如果想在页面切换时,不留下历史记录,也就是在浏览器最顶部左侧不会出现前进和后退按扭。我们只需要在<router-link>
标签上添加replace
属性(表示用当前路径替换之前路径)
修改以上案例中
<App>
组件中 所有<router-link>
标签内容如下:
<ul class="router-link">
<!--创建a标签链接 to属性最终转换为a标签的href属性值-->
<li>
<router-link to="/" replace active-class="active">网站首页</router-link>
</li>
<li>
<router-link to="/about" replace active-class="active"
>关于我们</router-link
>
</li>
<li>
<router-link to="/news" replace active-class="active">新闻中心</router-link>
</li>
</ul>
最终效果如下,注意观察,导航切换时,浏览器最顶部前进和后退按扭一直是不灰色,不可点状态。
# 5、访问router
实例和当前路由route
TIP
通过调用 app.use(router)
注册 vue-router 插件后。
选项式 API 中,我们可以在任意的组件中以
this.$router
访问到 router 实例 (即:createRouter()
方法返回的 router 实例)this.$route
访问到当前路由
组合式 API 中,我们可以在任意组件中,调用vue router
提供的
useRouter
函数访问到 router 实例useRoute
函数访问到当前路由
在任意组件的模板中,通过
$router
访问到 router 实例$route
访问到当前路由
路由实例方法查阅教程 (opens new window) | 路由对象属性查阅教程 (opens new window)
用以下代码,替换前面案例中的About
组件内容
<script>
export default {
data() {
// this.$router.currentRoute.value.path 当有url后面的路径值
console.log("选项式API:路由实例", this.$router.currentRoute.value.path);
console.log("选项式API:当前路由信息", this.$route.path);
return {};
},
};
</script>
<script setup>
import { useRouter, useRoute } from "vue-router";
console.log("组合式API:路由实例", useRouter().currentRoute.value.path);
console.log("组合式API:当前路由信息", useRoute().path);
</script>
<template>
<div>关于我们</div>
<div>路由实例:{{ $router.currentRoute.value.path }}</div>
<div>当前路由的路径:{{ $route.path }}</div>
</template>
最终渲染后效果如下:
# 6、嵌套路由
TIP
以下图中展示的效果就是一个嵌套路由效果
- 在点击
News
导航时,会显示对应组件的内容,在该组件中还存在二级导航,点击对应二级导航时,会加载不同的组件来显示不同内容。 - 我们把
/home
、/about
、/news
看作是一级路由,则/news/tab1
、/news/tab2
、/news/tab3
可以看成是二级路由。 - 并且这些路由显示的内容是嵌套在
/news
路由所在组件中,所以我们在定义路由时,需要把这些二级路由作为/news
路由的子路由。
以下代码为/news
一级路由定义了三个子路由 ,记得先用import
导入Tab1
、Tab2
、Tab3
(用以下代码替换前面案例中的对应代码)
{
path: "/news",
component: News,
// 所有子路由的书写方式和父路由一样,父路由对应子路由按以下方式写在children数组中
children: [
{
// 这里不需要加 / ,加/ 表示的是绝对路径 http://www.xx.com/tab1
// 不加表示相对父路由而言 http://www.xx.com/news/tab1
path: "tab1",
component: Tab1,
},
{
path: "tab2",
component: Tab2,
},
{
path: "tab3",
component: Tab3,
}
]
}
子路由是在父路由组件中显示的,所以我们需要在父路由组件News
中来定义子路由链接及路由组件内容渲染出口
用以下代码替换掉前面案例中的
News.vue
组件内容。
<!--News.vue 组件-->
<template>
<div class="menu">
<router-link to="/news/tab1">最新动态</router-link> |
<router-link to="/news/tab2">热门推荐</router-link> |
<router-link to="/news/tab3">历史动态</router-link>
</div>
<div class="main">
<router-view />
</div>
</template>
<style scoped>
.menu a {
font-size: 16px;
}
.router-link-active {
color: #fff;
background-color: skyblue;
padding: 5px;
border-radius: 10px;
}
</style>
按以上两步操作后,就可以实现如上图所示案例效果。
关于更深层级的路由嵌套和上面一样,一层一层嵌套下去就好。
# 7、链接精确激活时 Class 类名
TIP
默认情况下,链接精确激活时会加上router-link-exact-active
Class 类名。
链接精确激活与链接激活的区别
- 精确激活: 当地址栏链接为
/news/tab1
时,则只有链接/news/tab1
对应的 a 标签会被添加router-link-exact-active
Class 类,此时/news/tab1
链接为精确激活状态 - 激活:当地址栏链接为
/news/tab1
时,链接/news
和/news/tab1
对应的 a 标签会被添加router-link-active
Class 类名,此时/news/tab1
和/news
链接为激活状态
激活状态的链接中包含精确激活状态的链接。
下图是链接地址为/news/tab
时的截图,我们可以看/news
和/news/tab1
对应的 a 标签都加上激活状态的 class 类名,但只有/news/tab1
对应的 a 标签加上了精确激活的 class 类名
如果精确激活的链接样式包含了激活链接的样式,则我们只需要针不同部分的样式,给精确激活的链接添加router-link-exact-active
类名来实现。
exact-active-class 属性
我们可以通过<router-link>
标签的 exact-active-class
属性来自定义精确激活链接时添加的 Class 类名
<router-link to="/news/tab1" exact-active-class="exact-active"
>最新动态</router-link
>
# 8、命名路由
TIP
在定义路由时,我们可以为路由添加name
属性来指定路由的名字
const routes = [
{
name: 'home', // 路由名字,名字自定义,不一定是home
path: "/", // 路径
component: Home, // 路径对应渲染的组件
},
{
name: 'about',
path: "/about",
component: About,
},
{
name: 'news',
path: "/news",
component: News,
children: [
{
name:'tab1' // 路由名字
path: "tab1",
component: Tab1,
},
{
path: "tab2",
component: Tab2,
},
{
path: "tab3",
component: Tab3,
}
]
}
]
有了name
属性后,我们可以向<rotuer-link>
组件的 to 属性传递一个对象,来实现路由的跳转。
<!--以下方式,会根据name属性来找到指定的路由中的path值,实现路由跳转-->
<router-link :to="{ name: 'home' }" active-class="active">Home</router-link> |
<router-link :to="{ name: 'about' }" active-class="active">About</router-link> |
<router-link :to="{ name: 'news' }" active-class="active">News</router-link>
<!--以上代码,与以下代码实现的效果一模一样-->
<router-link to="/" active-class="active">Home</router-link> |
<router-link to="/about" active-class="active">About</router-link> |
<router-link to="/news" active-class="active">News</router-link>
当<router-link>
to 的属性值为一个对象时,name 属性与 path 属性只需要写一个即可
<!--以下写法是错的-->
<router-link :to="{name:'home',path:'/'}" active-class="active"
>Home</router-link
>
<!--以下两种写法是对的-->
<router-link :to="{name:'home'}" active-class="active">Home</router-link> |
<router-link :to="{path:'/'}" active-class="active">Home</router-link> |
注:
当我们的路由名很长很复杂时,在<router-link>
标签中可以通过name
属性来简化,而不需要书写path
属性
# 9、路由重定向
TIP
当我们访问某个路径时,我们希望他能重定向到其它的路径,比如访问/news
时,希望重定向到到/news/tab1
。
我们就可以在路由的配置中添加redirect
属性来实现路由的重定向。
- 重定向的目标可以是一个字符串路径
{
name: 'news',
path: "/news",
component: News,
redirect: "/news/tab1", // 重定向到 /news/tab1
children: [
{
name: 'tab1',
path: "tab1",
component: Tab1,
},
// ....此处省略部分代码
]
}
- 重定向的目标可以是一个命名的路由 (采用路由对象写法)
{
name: 'news',
path: "/news",
component: News,
redirect: { name: 'tab1' }, // 重定向到路由命名name所在的路径
children: [
{
name: 'tab1',
path: "tab1",
component: Tab1,
},
// ....此处省略部分代码
]
}
- 重定向的目标也可以是一个方法,该方法的返回值可以是前面提到的 ”字符串路径“ 或 ”路由对象“ 中的一种
{
name: 'news',
path: "/news",
component: News,
redirect: (to) => {
// to为目标路由对象,此处为/news路由对象
// {fullPath: '/news', hash: '', query: {…}, name: 'news', path: '/news', …}
console.log(to)
return { path: '/news/tab1' }
}
children: [
{
name: 'tab1',
path: "tab1",
component: Tab1,
},
// ....此处省略部分代码
]
}
以上三种方式,最终都能实现,当我们访问/news
路由时,会重定向到/new/tab1
路由,具体效果如下
# 9.1、注意事项
TIP
如果重定向的路由没有子路由,则该路由中的component
可以省略不写,因为它从来没有被直接访问过
const routes = [
{
path:"/"
redirect:"/home"
// 此处可以没有component
},
{
name: 'home', // 名字自定义,不一定是home
path: "/home", // 路径
component: Home,
}
]
# 二、vue Router 路由传参
TIP
在路由进行跳转时,我们可以通过传参的形式为当前路由携带相关数据。
路由传参有以下两种形式:
- query 参数
- params 参数
# 1、路由的 query 参数
TIP
query 参数最终会以 key = value
键值对的形式出现在地址 ?
后面。
我们来看下面这个路由
const routes = [
{
name: "user",
path: "/user",
component: User,
},
// ....
];
我们在定义路由导航时,就可以通过以下两种方式来传递 query 参数
- query 参数的两种写法
直接在址后面以key=value
形式携带传递的数据
<!--id=001 为传递的参数数据-->
<router-link to="/user?id=001">用户中心</router-link>
将to
属性的值定义为一个路由对象,通过query
字段来传递参数
<router-link
:to="{
path: '/user',
query: {
id: '001',
title:'abc'
}
}"
>用户中心</router-link
>
<!-- 也可以采用如下写法 -->
<router-link
:to="{
name: 'user',
query: {
id: '001'
}
}"
>用户中心</router-link
>
- 接受 query 参数
在User.vue
组件中,接受传递的 query 参数,代码如下:
<script setup>
import { useRoute } from "vue-router";
// 当前路由对象
const route = useRoute();
// 读取query参数
console.log(route.query.id); // 001
</script>
<template>
<div>用户中心</div>
<!--$route.query.id 读取传递的id,值为 001-->
<div>query参数:{{ $route.query.id }}</div>
<div>query参数:{{ route.query.id }}</div>
</template>
最终
User.vue
组件渲染后效果如下:
# 1.1、实战应用:根据 query 参数渲染数据
TIP
- 当我们点击不同的新闻标题时,需要把当前新闻的
id
作为参数传递给到Detail
组件 Detail
组件接受传递过来的id
值,向后端发请求获取当前 Id 对应的新闻详细内容,然后渲染在页面中
实现步骤
- 在前面项目的基础上,在
views/news
目录下新建Detail
组件 - 在
routes
配置中,/news/detail
路由定义为/news
的子路由,因为/news/detail
路由对应的组件最终被渲染后显示在News
组件中
const routes = [
// ...省略部分代码
{
name: 'news',
path: "/news",
component: News,
redirect: { name: 'tab1' }, // 重定向到路由命名name所在的路径
children: [
// 因为该组件内容显示在 News组件中,所以定义为他的子路由
{
name: "detail",
path: 'detail',
component: Detail
},
{
name: 'tab1',
path: "tab1",
component: Tab1,
}
// ....省略部分代码
]
}
- 修改组件 Tab1 的内容如下
<script setup>
import { reactive } from "vue";
const list = reactive([
{
id: "001",
title: "新闻标题1111",
},
{
id: "002",
title: "新闻标题2222",
},
{
id: "003",
title: "新闻标题3333",
},
]);
</script>
<template>
<div>最新动态内容</div>
<ul>
<li v-for="{ id, title } in list">
<!-- 方式一
<RouterLink :to="`/news/detail?id=${id}`">{{ title }}</RouterLink>
-->
<!--以下把path去掉,改用name="detail" 也可以-->
<RouterLink
:to="{
path: '/news/detail',
query: {
id: `${id}`
}
}"
>{{ title }}</RouterLink
>
</li>
</ul>
</template>
<style scoped>
ul li {
line-height: 35px;
border-bottom: 1px dashed #ddd;
}
ul li a {
font-size: 16px;
color: #666;
}
</style>
- 在
Detail
组件中接受传递的id
参数,并根据 id 查找满足条件的新闻,将新闻标题和内容显示在页面中
<script setup>
import { ref } from "vue";
import axios from "axios";
import { useRoute } from "vue-router";
// 获取当前路由
const route = useRoute();
// 接受传递的参数id
const id = route.query.id;
// 保存请求回来的新闻详情
const info = ref({});
// 根据id来发请求,获取当前新闻的详细内容
axios
.get(
`https://www.fastmock.site/mock/6ec78e345df340241e1f5043f0167833/icode/detail/${id}`
)
.then((res) => {
info.value = res.data.data;
})
.catch((err) => {
console.log(err);
});
</script>
<template>
<h3>{{ info.title }}</h3>
<div class="main">{{ info.content }}</div>
</template>
# 2、路由的 params 参数
TIP
以params
形式传参,需要在配置路由时,以:key
形式先占位。
如下:
const routes=[
// ....
{
name:'detail',
// 能匹配detail/12 detail/ab 不能匹配detail/12/b
path:'detail/:id',
component:Detail
},
{
path:'add/:id/:typeid
// path:'add/:id/a/:typeid'
component:Add'
}
// ......
]
}
// ....
]
在
<router-link>
组件中,to 属性的值可以写成一个路由对象,params
属性表示传递的参数。
注意:
以 params 形式传参时,只能通过name
属性来指定要跳转的链接,不能用path
属性。
<RouterLink
:to="{
name: 'detail',
params: {
id: '001'
}
}"
>{{ title }}</RouterLink
>
<!--以下为错误写法,params只能与name属性配合使用 -->
<RouterLink
:to="{
path: '/news/detail/',
params: {
id: '001'
}
}"
>{{ title }}</RouterLink
>
在组件中可以通过params.id
形式来访问到传递的 params 参数 id 等。
<script setup>
import { useRouter, useRoute } from "vue-router";
console.log("参数id:", useRoute().params.id);
</script>
<template>
<div>params参数:{{ $route.params.id }}</div>
</template>
# 2.1、实战应用:根据 params 参数渲染数据
TIP
针以前面的query
参数案例,我们只需做以下相关修改,就可以实现与之相同的效果
- 修改路由配置,在路由中添加
:id
占位符
const routes = [
// .....
{
name: "news",
path: "/news",
component: News,
redirect: { name: "tab1" }, // 重定向到路由命名name所在的路径
children: [
{
name: "detail",
path: "detail/:id",
component: Detail,
},
// ....
],
},
];
- 修改
Tab1.vue
中<route-link>
组件内容如下: (把 query 改成了 params)
<RouterLink
:to="{
name: 'detail',
params: {
id: `${id}`
}
}"
>{{ title }}</RouterLink
>
- 将
Detail.vue
组件中的route.query.id
修改成route.params.id
即可
// 接受传递的参数id
const id = route.params.id;
# 3、路由的 props 配置
TIP
路由的 props 配置可以让路由组件以 props 的形式来接受传递的 params 或 query 参数,写法更简洁。
在没有设置
props
属性前,在路由组件中只能以如下方式接受params
参数
<script setup>
import { useRouter, useRoute } from "vue-router";
console.log("参数id:", useRoute().params.id);
</script>
<template>
<div>参数:{{ $route.params.id }}</div>
</template>
有了 props 配置后,可以以 props 形式来接受传递的参数,如下写法更简洁
<script setup>
// 这里的属性名,必需要与路由组件的参数名相同
const props = defineProps(["id"]);
console.log("id参数", props.id);
</script>
<template>
<div>参数:{{ props.id }}</div>
</template>
# 3.1、props 布尔模式
TIP
当 props 的值为布尔值 true 时,相当于route.params
将被设置为组件的props
。
即:把所有 params 参数作为 props 传递给路由组件。
// 定义一些路由
const routes = [
// ...
{
name: "detail",
path: "detail/:id",
component: Detail,
// route.params将设置为组件的props
// 相当于在组件中 <Detail v-bind:=route.params />
props: true,
},
];
我们可以在Deatil
组件中以 props 的形式来接受传递的params
参数
<script setup>
import { ref } from "vue";
import axios from "axios";
// 接受params形式传递的参数 ----------------------
const props = defineProps(["id"]);
const id = props.id;
const info = ref({});
// 根据id来发请求,获取当前新闻的详细内容
axios
.get(
`https://www.fastmock.site/mock/6ec78e345df340241e1f5043f0167833/icode/detail/${id}`
)
.then((res) => {
info.value = res.data.data;
})
.catch((err) => {
console.log(err);
});
</script>
<template>
<h3>{{ info.title }}</h3>
<div class="main">{{ info.content }}</div>
</template>
# 3.2、props 对象模式
TIP
当props
是一个对象时,这个对象会被设置为组件的 props。
// 定义一些路由
const routes = [
// ...
{
name: "detail",
path: "detail/:id",
component: Detail,
// route.params将设置为组件的props
// 相当于在组件中 <Detail v-bind:={a:1,b:2} />
props: { a: 1, b: 2 },
},
];
我们可以在路由组件中以props
的形式来接受 props 配置传递的数据
<script setup>
const props = defineProps(["a", "b"]);
console.log("参数a", props.a); // 1
console.log("参数b", props.b); // 2
</script>
<template>
<div>关于我们</div>
<div>参数a:{{ props.a }}</div>
<div>参数b:{{ props.b }}</div>
</template>
# 3.3、props 函数模式
TIP
当 props 的值是一个函数时,允许返回值是一个 props 对象,函数的第一个参数为当前route
路由对象。
我们可以利用 props 的函数模式,实现以下功能:
- 将传递的
query
参数作为 props 传递给路由组件 - 将传递的
query
参数与静态值一起作为 props 传递给路由组件 - 将传递的
params
参数与静态值一起作为 props 传递给路由组件
将传递的query
参数作为 props 传递给路由组件
- 定义路由导航
<router-link to="/about?id=001">关于我们</router-link>
- 定义路由
const routes = [
// .....
{
name: "about",
path: "/about",
component: About,
// 写法一 将query参数作为props传递
props: (route) => route.query,
},
];
- 路由组件中通过 props 接受传递的 query 参数
const props = defineProps(['id');
将传递的query
参数与静态值一起作为 props 传递给路由组件
- 定义路由导航
<router-link to="/about?id=001&title=123">关于我们</router-link>
<!-- 或 -->
<router-link
:to="{
name: 'about',
query: {
id: '001',
title: '123'
}
}"
>关于我们</router-link
>
- 定义路由
const routes = [
// ....
{
name: "about",
path: "/about",
component: About,
alias: "/myabout",
// 将query参数与静态值组合,一起作为props传递
props: (route) => ({
id: route.query.id,
title: route.query.title,
msg: "其它数据",
}),
},
];
- 路由组件中通过 props 接受传递的 query 参数
const props = defineProps(["id", "title", "msg"]);
将传递的params
参数与静态值一起作为 props 传递给路由组件
- 定义路由导航
<router-link
:to="{
name: 'about',
params: {
id: '001',
title: '1233'
}
}"
>关于我们</router-link
>
- 定义路由
const routes = [
// ....
{
name: "about",
path: "/about/:id/:title",
component: About,
alias: "/myabout",
// 写法三:将params参数与静态值组合,一起作为props传递
props: (route) => ({
id: route.params.id,
title: route.params.title,
msg: "其它数据",
}),
},
];
- 路由组件中通过 props 接受传递的 query 参数
const props = defineProps(["id", "title", "msg"]);
# 4、响应路由参数的变化
TIP
我们来看下面这个带参的路由
const routes = [
{
name: "news", // 路由名
path: "/news/:id", // 路径
component: News, // 路径需要渲染的组件
},
];
当用户从/news/1001
导航到/news/1002
或/news/1003
时,相同的组件实例将被重复使用。
因为 3 个路由都渲染同个News
组件,比起销毁再创建,复用则显得更加高效。不过,这也意味着组件的生命周期钩子不会被调用,所以当路由的参数发生变化时,在<script setup>
中并不能获取到变化后的参数。
<script setup>
import { useRoute } from "vue-router";
const route = useRoute();
const id = route.params.id;
const url = "http://wwww.xxx.com/...."; // 请求数据源
// 只能在刚进到/news/1001时才能拿到id=1001。
// 后面从从/news/1001导航到/news/1002或/news/1003时,拿不到变化后的id
axios.get(`${url}${id}`).then((res) => {
// 发请求拿数据
});
</script>
要对同一个组件中参数的变化做出响应的话,你可以简单地 watch route
对象上的任意属性
<script setup>
import { useRoute } from "vue-router";
const route = useRoute();
const url = "http://wwww.xxx.com/...."; // 请求数据源
// 侦听 route.params的变化
watch(
() => route.params,
(newValue, oldValue, onCleanup) => {
// 对路由的变化做出响应
axios.get(`${url}${newValue.id}`).then((res) => {
// 发请求拿数据
});
}
);
</script>
# 4.1、实战应用
TIP
我们来实现如下效果,当用户从/news/1001
导航到/news/1002
或/news/1003
时都能拿到变化后的参数,然后根据参数的值来发请求获取新闻数据列表。
src/router/router.js
创建路由实例
// 1、从vue-router中解构两个方法
import {
createRouter,
createWebHashHistory,
createWebHistory,
} from "vue-router";
import News from "../views/News.vue";
// 定义一些路由:路径与组件的映射关系....
const routes = [
{
name: "home",
path: "/",
redirect: "/news/1001",
},
{
name: "news",
path: "/news/:id",
component: News,
},
];
// 创建router 路由实例
const router = createRouter({
// 路由模式
// history:createWebHashHistory(), // hash模式的路由
history: createWebHistory(),
// 配置一些路由
// routes:routes
routes,
});
// 对外暴露
export { router };
App.vue
中,创建路由导航
<template>
<ul class="router-link">
<li>
<router-link to="/news/1001">最新动态</router-link>
</li>
<li>
<router-link to="/news/1002">执门推荐</router-link>
</li>
<li>
<router-link to="/news/1003">历史动态</router-link>
</li>
</ul>
<!-- url对应组件内容输出口 -->
<div class="router-view">
<router-view></router-view>
</div>
</template>
<style>
.router-link {
display: flex;
justify-content: center;
text-align: center;
list-style: none;
margin-top: 30px;
}
.router-link li {
margin: 0 10px;
}
.router-link li a {
color: #000;
font-size: 16px;
text-decoration: none;
}
.router-link li a:hover {
color: tomato;
}
.router-link li a.router-link-active {
color: tomato;
}
.router-view {
width: 80%;
margin: 30px auto;
font-size: 20px;
min-height: 300px;
background-color: rgb(251, 249, 249);
}
</style>
<script setup>
import { ref, watch } from "vue";
import axios from "axios";
import { useRoute } from "vue-router";
const route = useRoute();
const list = ref([]);
const url =
"https://www.fastmock.site/mock/6ec78e345df340241e1f5043f0167833/icode/new/list/";
// 用来取消请求的对象
let controller = null;
// 侦听器侦听 route.params 的变化
watch(
() => route.params,
(newValue, oldValue, onCleanup) => {
controller = new AbortController();
// 发请求,拿数据
axios
.get(`${url}${route.params.id}`, {
// 配置取消请求
signal: controller.signal,
})
.then((res) => {
list.value = res.data.data;
})
.catch((err) => {
console.log(err.message);
});
// 取消请求
function cancle() {
controller.abort();
}
// 取消之前的请求
onCleanup(cancle);
},
{
immediate: true,
}
);
</script>
<template>
<ul>
<li v-for="{ id, title } in list">
<router-link to=""> {{ title }}</router-link>
</li>
</ul>
</template>
<style scoped>
ul {
padding: 20px;
}
ul li {
line-height: 35px;
border-bottom: 1px dashed #ddd;
text-indent: 2em;
}
ul li a {
color: #333;
text-decoration: none;
}
</style>
# 5、总结
TIP
本小节重点掌握路由传参和路由的 props 配置
路由传参两种方式:路由传递参数有 query 传参 和 params 传参 两种方式。
具体如下:
传参方式 | 特点与用法 |
---|---|
query 参数 | query 传递显示参数,在地址栏中明确知道那部分是参数 query 参数在 <script setup> 中通过useRoute().query.id 形式获取,在模板中以$route.query.id 形式获取 |
params 参数 | parmas 传递,不会显示参数,所以 params 传参相比 query 传参更安全一些 params 参数在 <script setup> 中通过useRoute().params.id 形式获取,在模板中以$route.params.id 形式获取 |
# 5.1、路由 props 配置
TIP
路由 props 配置的主要作用:
- 使路由组件能以 props 的形式来接受传递的参数,写法更简洁。
- 使路由组件可以以 props 形式接受一些静态数据。
路由 props 配置的三种写法,如下:
值的三种写法 | 应用场景 |
---|---|
布尔值 | 当我们需要把params 参数作为 props 传递给路由组件时,props 的值为true |
对象写法 | 当我们需要给路由组件传递一些静态的 props 时,可以采用对象写法 |
函数写法 | 当我们需要把路由的query参数 或params 参数与一些静态值一起作为 props 传递给路由组件时,可以采用函数写法 |
# 5.3、响应路由参数的变化
TIP
当路由带参时,比如/news/:id
路由,当用户从/news/1001
导航到/news/1002
时,相同的组件实例将被重复使用,所以组件的生命周期钩子不会被调用,这样造成没有办法获取到变化后的参数值。
要对同一个组件中参数的变化做出响应的话,你可以简单地 watch $route
对象上的任意属性。
import { useRoute } from "vue-router";
const route = useRoute();
watch(
() => router.params,
() => {}
);
# 三、路由别名
TIP
在路由配置时,我们可以通过alias
属性为路由取别名。
- 当路由
/about
的别名为/myabout
时,我们通过地址/myabout
访问的是/about
路由的内容,但路由地址显示的是/myabout
- 当路由
/news/tab2
的别名为/newsInfo
时,我们通过地址/newsInfo
访问的是/news/tab2
路由的内容,但地址显示的是/newsInfo
通过别名,你可以自由地将 UI 结构映射到一个任意的 URL,而不受配置的嵌套结构的限制
# 1、别名是一个绝对或相对路径
TIP
别名可以是一个以/
开头的绝对路径,也可以是一个没有/
开头的相对路径
const routes = [
// 省略部分代码......
{
name: 'about',
path: "/about",
component: About,
alias: "/myabout" // 别名 绝对路径,访问地址 /myabout
},
{
name: 'news',
path: "/news",
component: News,
redirect: { name: 'tab1' },
children: [
name: 'tab1',
path: "tab1",
component: Tab1,
},
{
path: "tab2",
component: Tab2,
alias: '/newsInfo', // 别名 ,绝对路径 访问地址 /newsInfo
},
{
path: "tab3",
component: Tab3,
alias:"commonInfo" // 别名,相对路径 访问地址 /news/commonInfo
}
]
}
]
接下来,我们可以把页面中访问路由的地址修改为访问别名,如下
<ul class="router-link">
<li><router-link to="/">网站首页</router-link></li>
<li><router-link to="/myabout">关于我们</router-link></li>
<li><router-link to="/newsInfo">热门推荐</router-link></li>
<li><router-link to="/news/commonInfo">历史动态</router-link></li>
</ul>
最终渲染效果如下:
# 2、别名是一个数组
TIP
别名可以由多个以相对或绝对路径组成的数组
路由
/news/tab3
的别名是一个数组,如下:
const routes = [
// ......
{
name: "news",
path: "/news",
component: News,
redirect: { name: "tab1" },
children: [
// ......
{
path: "tab3",
component: Tab3,
// /Info /news/commonInfo 最终访问的都是 /news/tab3路由的内容
alias: ["/Info", "commonInfo"],
},
],
},
];
我们通过
/Info
/news/commonInfo
最终访问的都是/news/tab3
路由的内容
# 3、别名携带参数
TIP
如果路由有参数,一定要在任何绝对别名中包含它们
const routes = [
// .....
{
name: "about",
path: "/about/:id",
component: About,
// 可以通过 /about/1001 、 /myabout/1001/ 、 /1001 访问到about关于我们页面
alias: [
"/myabout/:id", // 绝对路径必须带上参数
"/:id",
],
},
];
以下导航访问的都是同一个页面关于我们
<li><router-link to="/about/1001">关于我们</router-link></li>
<li><router-link to="/myabout/1001">关于我们</router-link></li>
<li><router-link to="/1001">关于我们</router-link></li>
# 四、命名视图
TIP
本小节我们讲解命名视图和嵌套命名视图
# 1、命名视图
TIP
有时候想同时(同级)展示多个视图,而不是嵌套展示。例如创建一个布局,有 header(头部)、main(主内容)、footer(底部)三个视图,这个时候命名视图就派上用场了。
你可以在界面中拥有多个单独命名视图,而不是只有一个单独的出口,如下:
<router-view name="Header"></router-view>
<router-view></router-view>
<!-- 没有name属性,默认为name='default' 上面写法等同于下面写法-->
<!-- <router-view name="default"></router-view> -->
<router-view name="Footer"></router-view>
如果
router-view
没有设置 name 名字,那么默认为name="default"
。
一个视图使用一个组件渲染,因此对于同个路由,有多个视图就需要多个组件渲染。确保正确使用 components
配置 (带上 s):
const router = createRouter({
history: createWebHashHistory(),
routes: [
{
path: "/",
components: {
default: Main,
// Header: Header 的缩写
Header,
// 它们与 `<router-view>` 上的 `name` 属性匹配
Footer,
},
},
],
});
# 2、命名视图应用
TIP
我们利用命名视图实现如下图所示的效果
App.vue
<script setup>
import Header from "./views/Header.vue";
</script>
<template>
<header></header>
<!--多个命名视图, 注意这里的名字采用的是小写-->
<router-view name="header"></router-view>
<router-view></router-view>
<router-view name="footer"></router-view>
</template>
Header.vue
<template>
<div class="header">
<ul class="router-link">
<li><router-link to="/">网站首页</router-link></li>
<li><router-link to="/about">关于我们</router-link></li>
<li><router-link to="/news">新闻中心</router-link></li>
</ul>
</div>
</template>
<style scoped>
.header {
height: 50px;
}
.router-link {
display: flex;
justify-content: center;
text-align: center;
list-style: none;
}
.router-link li {
line-height: 50px;
margin: 0 10px;
}
.router-link li a {
color: #000;
font-size: 16px;
text-decoration: none;
}
.router-link li a:hover {
color: tomato;
}
.router-link li a.router-link-active {
color: tomato;
}
</style>
router/router.js
import { createRouter, createWebHistory } from "vue-router";
import HomeHeader from "../views/HomeHeader.vue";
import HomeMain from "../views/HomeMain.vue";
import HomeFooter from "../views/HomeFooter.vue";
import AboutHeader from "../views/AboutHeader.vue";
import AboutMain from "../views/AboutMain.vue";
import NewsMain from "../views/NewsMain.vue";
const routes = [
{
path: "/",
// 当前路由对应多个组件
components: {
header: HomeHeader, // 对应默认视图
default: HomeMain, // 对应命名视图 name='main'
footer: HomeFooter, // 对应命名视图 name='footer'
},
},
{
path: "/about",
components: {
header: AboutHeader, // 对应默认视图
default: AboutMain,
},
},
{
path: "/news",
components: NewsMain,
// 如果只渲染默认视图, components:{ default:NewHeader }可以简写成
// component:NewHeader
},
];
const router = createRouter({
history: createWebHistory(),
routes,
});
export { router };
# 3、嵌套命名视图
TIP
如果上面案例中 /news
路由还存在子路由,子路由对应的页面也可以由多个命名视图来展示
NewsMain.vue
<template>
<div class="router-link">
<router-link to="/news/tab1">最新动态</router-link>
</div>
<div class="router-view">
<router-view name="Left" class="left"></router-view>
<router-view name="Right" class="right"></router-view>
</div>
</template>
<style scoped>
.router-view {
display: flex;
justify-content: space-between;
}
</style>
router/router.js
const routes = [
{
path: "/news",
component: NewsMain,
children: [
{
path: "tab1",
components: {
Left: TabLeft1,
Right: TabRight1,
},
},
],
},
];
# 五、动态路由的匹配语法
TIP
本小节我们来学习动态路由的匹配语法,主要内容有:
- 参数中自定义正则
- 可重复的参数
- 可选参数
- 注意事项
- 捕获 404 Not Found 路由
- Sensitive 与 strict 路由配置
# 1、参数中自定义正则
TIP
当我们使用user/:userId
这样的动态路由时,:userId
为路径参数,他能匹配任意的字符,所以user/12
、user/ab
都能匹配成功。
如果我们希望:userId
只能匹配数字,也就是user/12
能匹配成功,但user/ab
会匹配失败。我们可在路径参数 后面的括号中加入正则表达式来限定
const routes = [
{
// 只能匹配 /user/1 /user/123 等 但不能匹配 /user/ab
path: "/user/:userId(\\d+)",
},
];
注意:
字符中的\
反斜杆有特殊用途,所以要加上\\
来转义,确保能正确匹配\d
如果我们希望路由/user/:userId
后面的:userId
只能匹配数字或字母类字符,我们可以在路径参数后面的括号加入正则表达式来限定
const routes = [
{
// 只能匹配 /user/1 /user/123 等 但不能匹配 /user/ab
path: "/user/:userId([a-zA-Z0-9]+)",
},
];
# 2、可重复的参数
TIP
如果你需要匹配具有多个部分的路由,如/user/:urls
可以匹配 /user/one
/user/one/two
、/user/one/two/123
等
则可以在路径参数后面使用 *
(0 个或多个)和 +
(1 个或多个)将参数标记为可重复
const routes = [
{
// 可以匹配 /user/one /user/one/two /user/one/two/123
// 不能匹配 /user/
path: "/user/:userId+",
},
{
// 可以匹配 /product/one /product/one/two /product/one/two/123
// 也能匹配 /user/
path: "/product/:productId*",
},
{
// 可以匹配 /news/12 /news/12/23 不能匹配 /news/a /news/12/b
// 只要重复的路径中包含非数字,都不能匹配成功
path: "/news/:id(\\d+)+",
},
];
# 3、可选参数
TIP
你可以在路径参数后面使用 ?
修饰符(0 个或 1 个)将一个参数标记为可选。
const routes = [
{
// 可以匹配 /user /user/ab /user/12 等
path: "/user/:userId?",
},
{
// 可以匹配 /news /news/12 不能匹配 /user/ab
path: "/news/:id(\\d+)?",
},
];
总结
+
表示 1 个或多个,同时参数可以重复*
表示 0 个或多个,同时参数可以重复?
表示 0 个或 1 个,参数不能重复
# 4、注意事项
我们来看下面两个路由
const routes = [
{
path: "/:keyword",
},
{
path: "/:id(\\d+)",
},
];
注:
当我们访问/12
时,或/
反斜杆后面跟着数字时,将匹配/:id(\\d+)
,其它情况将会匹配/:keyword
。
与/:id(\\d+)
和/:keyword
在 routes 数组中的顺序没有关系。
# 5、捕获 404 Not Found 路由
TIP
我们可以在定义routes
时,配置一个匹配所有路由的路由对象,该路由所渲染的组件为NotFound
显示 404 页面内容。
如果当前访问的路径没有被/:pathMatch(.*)
之外的路由匹配,则就会被/:pathMatch(.*)
匹配,显示NotFound
组件
const routes = [
// .......
{
name: "NotFound",
// 匹配任意路由
path: "/:pathMatch(.*)*",
component: NotFound,
},
// .......
];
# 6、Sensitive 与 strict 路由配置
TIP
默认情况下路由/users
将匹配 /users
、/users/
、甚至 /Users/
。我们可以在createRouter(options)
的 options 中来配置sensitive
与strict
选项来区分大小写要禁用尾部斜线。
- sensitive :设置路由是否区分大小写,true 表示区分大小写,false 表示不区分,默认值为 fasle
- strict :路由是否禁止尾部斜线 true 表示禁用,false 表示不禁用,默认值为 false
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: "/about",
component: About,
},
{
path: "/news",
component: News,
},
],
strict: true, // 禁止尾部斜线
sensitive: true, // 区分大小写
});
以上/about
路由只能与/about
匹配,与/About
和/about/
都不会匹配成功。/news
路由只能与/news
匹配,与/News
和/news/
都不会匹配成功。
sensitive 与 strict 选项即可以如上面一样应用在整个全局路由上,又可以应用于当前路由上,如下:
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: "/about",
component: About,
strict: true, // 禁止尾部斜线
},
{
path: "/news",
component: News,
sensitive: true, // 区分大小写
},
],
});
注:
- 以上
/about
路由可以与/about
和/About
匹配成功,但与/about/
匹配失败 - 以上
/news
路由可以与/news
和/news/
匹配成功,但与/News
匹配失败
# 六、vue Router 编程式导航
TIP
除了使用 <router-link>
创建 a 标签来定义导航链接,我们还可以借助 router 的实例方法,通过编写代码来实现。
- 在组件中插入
<router-link>
组件来创建导航,属于声明式写法 - 通过
router
实例方法来创建导航,属于编程式导航写法。
声明式 | 编程式 |
---|---|
<router-link :to="..."> | router.push(...) |
以下表格中列出的 router 实例方法,可以用来实现页面导航
router 实例方法 | 功能 |
---|---|
push() | 用来导航到一个新的 URL |
replace() | 用来导航到一个新的 URL,但会替换掉之前的 URL,无法后退到之前 URL |
go() | 导航到指定记录,用于前进或后退 |
back() | 相当于后退按扭,后退到前一页 |
forward() | 相当于前进按扭,前进到前一页 |
# 1、push 方法
TIP
push 方法用来导航到一个新的 URL,他接受一个参数,该参数与<router-link>
组件中 to 属性值的写法一模一样,可以是一个字符串路径,或者一个描述地址对象。
// 字符串路径
router.push("/news/tab1");
// 带有路径的对象
router.push({ path: "/news/tab1" });
// 命名的路由,并加上参数,让路由建立 url
router.push({ name: "tab1", params: { id: "001" } });
// 带query查询参数,结果是 /news/tab1?id=001
router.push({ path: "/news/tab1", query: { id: "001" } });
// 带 hash,结果是 /about#team
router.push({ path: "/about", hash: "#team" });
注意事项
params
参数只能与name
属性配合,不能与path
属性配合,以下写法 params 会被忽略
// 错误写法
router.push({ path: "/news/tab1", params: { id: "001" } });
# 2、实战应用
TIP
接下来,我们利用编程式导航实现下图所示的导航切换
- 在
src
目录下新建views
目录,在此目录所需要的路由组件
views
├─ Home.vue // 首页组件
├─ Login.vue // 登录组件
├─ Register.vue // 注册组件
- 各个路由组件内容如下
<!--Home.vue-->
<template>
<h3>网站首页</h3>
</template>
<!--Login.vue-->
<template>
<h3>用户登录</h3>
</template>
<!--Register.vue-->
<template>
<h3>用户注册</h3>
</template>
- 在
src
目录下新建router
目录,在此目录下新建index.js
文件,用来定义路由
import { createRouter, createWebHistory } from "vue-router";
import Home from "../views/Home.vue";
import Login from "../views/Login.vue";
import Register from "../views/Register.vue";
import User from "../views/User.vue";
// 定义一些路由
const routes = [
{
name: "home",
path: "/",
component: Home,
},
{
name: "login",
path: "/login",
component: Login,
},
{
name: "register",
path: "/register",
component: Register,
},
];
// 创建路由实例
const router = createRouter({
history: createWebHistory(),
routes,
});
// 对外暴露
export { router };
App.vue
组件
<script setup>
import { useRouter } from "vue-router";
// 获取router实例
const router = useRouter();
// 切换URL方法
function goTo(url) {
router.push(url); // 切换到对应URL
}
</script>
<template>
<button @click="goTo('/login')">登录</button> |
<button @click="goTo('/register')">注册</button>
<div class="main">
<router-view></router-view>
</div>
</template>
<style>
.main {
margin-top: 50px;
display: flex;
justify-content: center;
align-items: center;
}
</style>
# 3、replace 方法
TIP
与 push 方法一样用来导航到一个新的 URL,但会替换掉之前的 URL,无法后退到之前 URL
声明式 | 编程式 |
---|---|
<router-link :to="..." replace> | router.replace(...) |
router.replace({ path: "/home" });
如果把上面案例中的 push 方法,换成 replace 方法,发现浏览器顶部左侧的前进后退按扭一直是灰色的。
function goTo(url) {
router.replace(url); // 切换到对应URL
}
# 4、go、back、forward 方法
router.go(1); // 向前移动一页,相当于前进按扭
router.back(); // 返回前一页 ,相当于后退按扭
router.forward(); // 与go(1) 是一样的
把上面案例
App.vue
中代码更改成如下:
<script setup>
import { useRouter } from "vue-router";
const router = useRouter();
function goTo(url) {
router.push(url);
}
function go() {
router.go(1);
}
function back() {
router.back();
}
</script>
<template>
<button @click="goTo('/login')">登录</button> |
<button @click="goTo('/register')">注册</button> |
<button @click="go">前进</button> |
<button @click="back">后退</button>
<div class="main">
<router-view></router-view>
</div>
</template>
<style>
.main {
margin-top: 30px;
display: flex;
justify-content: center;
align-items: center;
}
</style>
最终渲染效果如下,先点击登录、注册、再点击后退会退到登录页,再点前进按扭,会前进到注册页。
# 5、总结
TIP
你可能已经注意到,router.push
、router.replace
和 router.go
是 window.history.pushState
、window.history.replaceState
和 window.history.go
(opens new window) 的翻版,它们确实模仿了 window.history
的 API。
因此,如果你已经熟悉 Browser History APIs (opens new window),在使用 Vue Router 时,操作历史记录就会觉得很熟悉。
值得一提的是,无论在创建路由器实例时传递什么样的 history
配置 (opens new window),Vue Router 的导航方法( push
、replace
、go
)都能始终正常工作。
# 七、实战应用:项目框架搭建
TIP
本小节结合前面学习过的 Vant UI 与 Vue Router 实现一个简单的应用导航框架,具体效果如下。
# 1、实现步骤
TIP
- 路由设计
- 安装 Vant 组件库
- 实现页面路由
- 单页面开发
# 2、路由设计
TIP
首先根据当前应用的需求设计好当前应用的路由。
当前项目只涉及一级导航(路由),各路由关系与路由对应的组件如下表
页面 | 一级路由 | 路由组件 |
---|---|---|
首页 | / | Home |
购物车 | /mycart | MyCart |
好看 | /nice | Nice |
我的 | /my | My |
在src/router/index.js
中创建 router 实例,并对外暴露
import { createApp } from "vue";
import { createRouter, createWebHistory } from "vue-router";
import Home from "../views/Home.vue";
import MyCart from "../views/MyCart.vue";
import My from "../views/My.vue";
import Nice from "../views/Nice.vue";
const routes = [
{
path: "/",
component: Home,
},
{
path: "/mycart",
component: MyCart,
},
{
path: "/nice",
component: Nice,
},
{
path: "/my",
component: My,
},
];
const router = createRouter({
history: createWebHistory(),
routes,
});
export { router };
在src/main.js
中注册 router 实例
// .....此处省略部分代码
import { router } from "./router/";
// 注册路由
app.use(router);
// ......
# 3、安装 Vant 组件库
TIP
在此项目中,我们会用到 Vant 组件库,所以我们需要先安装好 Vant 组件库
- 安装 UI 组件库
npm i vant
- 按需引入组件,则需要安装以下插件
npm i unplugin-vue-components -D
- 在 vite.config.js 文件中配置好此插件
import vue from "@vitejs/plugin-vue";
import Components from "unplugin-vue-components/vite";
import { VantResolver } from "unplugin-vue-components/resolvers";
export default {
plugins: [
vue(),
Components({
resolvers: [VantResolver()],
}),
],
};
# 4、实现页面路由
TIP
根据路由实现各页面之间的链接(跳转)关系。
在此项目中,我主要构建当前应用底部的 Tabbar 导航。此导航采用 Vant 组件库中的 Tabbar 组件 (opens new window)实现。
<script setup>
import { ref } from "vue";
const active = ref(0);
</script>
<template>
<router-view></router-view>
<van-tabbar active-color="#ee0a24" v-model="active">
<van-tabbar-item icon="home-o" to="/">首页</van-tabbar-item>
<van-tabbar-item icon="shopping-cart-o" to="/mycart"
>购物车</van-tabbar-item
>
<van-tabbar-item icon="tv-o" to="/nice">好看</van-tabbar-item>
<van-tabbar-item icon="friends-o" to="/my">我的</van-tabbar-item>
</van-tabbar>
</template>
最终实现效果如下,点击对应的导航可以显示不同的内容
# 5、单页面开发
TIP
整个应用的页面路由(导航)实现好之后,我们就可以开发单个路由页面的功能了。
在这个应用中,每个页面(除首页)的顶部都有一个返回按扭,可以返回到到前一页。这里利用 Vant UI 的 NavBar 导航栏 (opens new window)组件来实现。
MyCart.vue
组件内容
<script setup>
// 返回前一页
function onClickLeft() {
history.back();
}
</script>
<template>
<!-- 导航栏 -->
<van-nav-bar
title="购物车"
left-text="返回"
left-arrow
@click-left="onClickLeft"
/>
<!--主体内容-->
<div class="main">购物车.....</div>
</template>
<style scoped>
.main {
text-align: center;
}
/* 修改导航栏中 < 返回 的颜色为黑色*/
:global(.van-nav-bar__text) {
color: #000;
}
:global(.van-nav-bar .van-icon) {
color: #000;
}
</style>
最终实现
/mycart
路由访问到的效果如下:
注:
其它带有返回导航栏的Nice
、My
组件的内容也按上面格式书写即可,针对修改导航栏中 < 返回
颜色的样式可以不用再重写。
大厂最新技术学习分享群
微信扫一扫进群,获取资料
X