今天总结下Vue3中路由相关的知识,大致分为以下4点:路由的理解,路由的引入与创建,非编程式路由导航,编程式路由导航。
1.路由的理解
单页面应用中,通过各种方式(点击或自动或条件跳转等等操作)使展示区中呈现路由组件。
各种方式
-
非编程式路由导航
-
编程式路由导航
展示区
写法为<routerView/>,vue-router提供的组件,使用时不需要引入,用于固定需要展示路由组件的位置。
路由组件和普通组件的区别
可以和普通组件做区分,路由组件和普通组件的区别:
-
普通组件一般需要手动写在某组件的<templete>标签体中,而路由组件是写在管理路由规则的文件中,通俗易懂的来说,普通组件写在html中,而路由组件写在js或ts中;
-
根据Vue3工程化写法的规则,普通组件存在于components命名的文件夹中,而路由组件存在于pages或views命名的文件夹中。
普通组件 Header: // src/App.vue <script setup lang="ts"> import Header from './components/Header.vue'; </script> <template> <Header/> </template> <style scoped> </style> 路由组件 Home: // src/router/index.ts import Home from '@/pages/Home.vue' const router = createRouter({ history: createWebHashHistory(), routes: [ { name: 'shouye', path: '/home', component: Home }, }) export default router
2.路由的引入和创建
引入
npm i vue-router
创建
- 创建router文件夹,创建index.ts文件,这里是工程化创建方式,不一定非要这样命名。
- 从vue-router中引入创建路由的api,称createRouter;引入要创建路由的模式,一个历史模式,一个哈希模式。
createWebHistory(History模式) 与 createWebHashHistory(Hash模式)的优缺点:// src/router/index.ts import { createRouter, createWebHistory, createWebHashHistory } from "vue-router"
createWebHistory(History模式) createWebHashHistory(Hash模式) 路径中没有#,很美观 路径中有#,不美观 需要后端配合处理 不需要后端处理 常用在购物网,产品介绍网站 常用在公司后台管理系统 - 引入路由组件(创建组件这里省略过程,跟普通组件一样,注意创建的位置就行)
// src/router/index.ts import { createRouter, createWebHistory, createWebHashHistory } from "vue-router" import Home from '@/pages/Home.vue' import About from '@/pages/About.vue' import News from '@/pages/News.vue' import Details from '@/pages/Details.vue'
- 创建路由规则,选择模式,不要忘记最后要把router暴露出去。
// src/router/index.ts import { createRouter, createWebHistory, createWebHashHistory } from "vue-router" import Home from '@/pages/Home.vue' import About from '@/pages/About.vue' import News from '@/pages/News.vue' import Details from '@/pages/Details.vue' const router = createRouter({ history: createWebHashHistory(), // createWebHistory:History模式 // createWebHashHistory:Hash模式 routes: [ { name: 'shouye', path: '/home, component: Home, }, { name: 'guanyu', path: '/about', component: About, }, { name: 'xinwen', path: '/news', component: News, children: [ { name: 'xiangqing', path: 'details', component: Details } ] } ] }) export default router
- 在入口文件main.ts中引入刚才创建好的路由规则,并且让vue使用它。这样我们的路由就已经创建好并使用规则了。
import './assets/main.css' import { createApp } from 'vue' import App from './App.vue' import router from "@/router"; // 引入刚才创建的路由规则 const app = createApp(App) app.use(router) // 一定要在挂载之前使用这个规则 app.mount('#app')
3. 非编程式路由导航
上方已经创建好了路由规则,我们该在路由组件中去创建路由导航区和路由展示区了。
使用场景
点击路由导航区来切换展示区中的路由组件。
路由导航区:
vue-router提供类似于a标签的组件<routerLink/>,标签体中可以写属性(push / replace)来决定跳转方法,默认为push方法。replace 属性替换当前路由,没有不可回退;而push添加新的历史记录,支持回退。
// src/App.ts
<script setup lang="ts">
</script>
<template>
<router-link to="/home" replace>首页</router-link> |
<router-link to="/about" push>关于</router-link>|
<router-link to="/news" push>新闻</router-link>
<router-view/>
</template>
<style scoped>
</style>
标签属性
to属性(重点)
通过to属性可以指定目标路由,to属性支持6种传参方式,如下:
// const userId = ref('aaaaa')
// const userName= ref('bbbbbb')
// 1.to的字符串写法传递query参数
<router-link to="/detail/?userId=${userId}&userName=${userName}">详情</router-link>
// 2.to的字符串写法传递param参数
<router-link to="/detail/${userId}/${userName}">详情</router-link>
// 3.to的对象写法通过path方式传递query参数
<router-link :to="{path: '/detail', query: {userId, userName}">详情</router-link>
// 4.to的对象写法通过path方式传递params参数
<router-link :to="{path: '/detail', params: {userId, userName}">详情</router-link>
// 5.to的对象写法通过name方式传递query参数
<router-link :to="{name: 'xiangqing', query: {userId, userName}">详情</router-link>
// 6.to的对象写法通过name方式传递params参数
<router-link :to="{name: 'xiangqing', params: {userId, userName}">详情</router-link>
不同传参类型的路由规则配置
to传递不同类型的参数(query或params),会影响路由规则中path属性的写法。
// src/router/index.ts
import { createRouter, createWebHashHistory } from "vue-router"
import News from '@/pages/News.vue'
import Detail from '@/pages/Detail.vue'
const router = createRouter({
history: createWebHistory(),
routes: [
{
name: 'xinwen',
path: '/news',
component: News,
// 注意:子组件path开头不加斜杠
children: [
{
name: 'xiangqing',
path: 'detail', // 1.传递query参数时,不用写占位符
component: Detail,
}
{
name: 'xiangqing',
path: 'detail/:userId/:userName' // 2.传递param参数时,path必须用占位符
component: Detail,
}
]
}
]
})
export default router
接收参数
子组件接收参数的方式也多种多样,这里距离两种常见的收参方式:
这里不展示同时传递两种类型参数的写法了,我选其中一种来进行演示。有兴趣的朋友可以自行研究一下,是可以同时传递的。
-
普通收参:子组件中拿到路由对象后需要手动解构出参数,对应的路由规则中不需要做任何额外变动。
// src/pages/detail.vue <template> <div>我是{{ query.userId}}-{{ query.userName}}</div> // 或者 <div>我是{{ params.userId}}-{{ params.userName}}</div> </template> <script setup lang="ts"> import { toRefs } from "vue"; import { useRoute } from "vue-router"; // 拿到路由 const route = useRoute() // 响应式的数据解构出来的属性并不会是响应式的,需要toRefs手动响应式 const { query, params } = toRefs(route) </script> <style scoped> </style>
// src/router/index.ts 不需要添加其他额外属性 children: [ { name: 'xiangqing', path: 'detail', component: Detail, } ]
-
简便收参:子组件直接通过defineProps把参数定义出来就可以使用了,但对应的路由规则需要添加props属性,props有两种写法。
// src/pages/detail.vue <template> <div>我是{{ userId }}-{{ userName }}</div> // 两种参数类型都可以直接用 </template> <script setup lang="ts"> defineProps(['userId ','userName ']) // 定义出参数就可以用了 </script> <style scoped> </style>
// src/router/index.ts 对应的子组件路由规则 // 1.布尔类型props .....略..... children: [ { name: 'xiangqing', path: 'detail', component: Detail, props: true // 布尔写法只能处理params参数 } ] // 2.函数类型props children: [ { name: 'xiangqing', path: 'detail', component: Detail, props(to) { // 函数写法既可以处理query参数,又可以处理params参数。 return { query: to.query, params: to.params } }, } ] .....略.....
4. 编程式路由导航
理解
已经到这里了,没有仔细看前面非编程式路由导航的朋友一定要回去瞅瞅,你会发现你对编程式路由导航的学习成本为0,不信?请您继续看。
vue-router提供了一个API,叫useRouter,使用其实例中的跳转方法(push / replace)来切换展示区中的路由组件。
使用场景
需要根据条件切换路由组件。
写法示例
需求:点击不同的按钮,不同秒数后携带不同的参数进行不同方式路由跳转。
// src/pages/detail.vue
<template>
<div>详情组件</div>
<button @click="jump(3000, true)">点击我3秒后使用默认模式push进入详情1</button>
<button @click="jump(5000, false)">点击我5秒后使用replace模式进入详情2</button>
<router-view/>
</template>
<script setup lang="ts">
import { useRouter } from "vue-router";
const router = useRouter() // 引入路由器
let timer = null
function jump(delay: number, jumpType: boolean) {
timer = setTimeout(() => {
if(jumpType){
router.push({ // 默认为push模式,可回退记录
name: 'xiangqing',
params: {
id: '11',
content: '1111'
},
})
}else{
router.replace({ // replace模式,不可回退。
name: 'xiangqing',
params: {
id: 'params1',
content: 'params2'
},
query: {
id: 'query3',
content: 'query4'
},
})
}
}, delay)
}
</script>
<style scoped>
</style>
发现没有朋友们,router.push(obj), 这个obj的写法,和前面的非编程式路由导航中的to写法一摸一样,没看懂的朋友可以看看前面对非编程式导航对to属性的详解。
所以编程式路由导航不仅简单,而且更加实用!