Vue Router基础
什么是Vue Router?
Vue Router是Vue.js的官方路由。 它与Vue.js核心深度集成,使得用Vue.js构建单页应用变得轻而易举。Vue Router提供了富有表现力、可配置的、方便的路由功能,包括直观且强大的语法来定义静态或动态路由,以及细致的导航控制,可以拦截任何导航并更精确地控制其结果。
为什么要使用Vue Router?
Vue Router 是 Vue 官方的客户端路由解决方案。客户端路由的作用是在单页应用 (SPA) 中将浏览器的 URL 和用户看到的内容绑定起来。当用户在应用中浏览不同页面时,URL 会随之更新,但页面不需要从服务器重新加载。
如果要学习 Vue Router 的进阶内容,请点击 Vue Router 进阶
Vue Router官方文档 https://router.vuejs.org/zh/
创建路由实例
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
import AboutView from '../views/AboutView.vue'
const routes = [
{ path: '/', component: HomeView },
{ path: '/about', component: AboutView }
]
const router = createRouter({
history: createWebHistory(),
routes
})
export default router
//在页面展示组件和跳转
<template>
<router-link to="/">Home</router-link>
<router-link to="/about">About</router-link>
<router-view></router-view>
</template>
路由模式
createWebHistory()
对应history
模式(http://localhost:8080/
)。
createWebHashHistory()
对应hash
模式(http://localhost:8080/#/
)。
RouterLink 组件
与常规的<a>
标签不同的是使得 Vue Router 能够在不重新加载页面的情况下改变URL
,处理URL
的生成、编码和其他功能。
RouterView 组件
使 Vue Router 知道在页面哪个位置渲染当前URL
路径对应的路由组件。
命名路由
// 创建路由
{ path: '/', name: 'home', component: HomeView }
// 使用路由
<router-link :to="{ name: 'home' }"></router-link>
使用 name 的优点
没有硬编码的 URL。
params 的自动编码/解码。
绕过路径排序,例如展示一个匹配相同路径但排序较低的路由。
注意:所有路由的命名都必须是唯一的。如果为多条路由添加相同的命名,路由器只会保留最后那一条。
动态路由匹配
什么是动态路由?
根据不同的参数动态地加载不同的路由配置和组件。允许应用程序根据用户输入的参数(如用户ID、商品ID等)来加载不同的页面内容,从而提高用户体验和应用程序的灵活性。
// :id表示一个动态参数
const routes = [
{ path: '/', name: 'home' },
{ path: '/about', name: 'about' },
{ path: '/user/:id', name: 'user' }
]
// 设置多个动态参数
{ path: '/user/:id/:name', name: 'user' } // -- /user/1/username { id: 1, name: 'username' }
{ path: '/user/:id/detail/:userId', name: 'user' } // -- user/1/detail/123 {id: 1, userId: 123 }
响应路由参数的变化
当从/users/1
导航到/users/2
时,相同的组件实例将被重复使用。因为两个路由都渲染同个组件,比起销毁再创建,复用则显得更加高效。但这也意味着组件的生命周期钩子不会被调用。使用watch
对任意属性进行响应式的监听。
<script setup>
import { watch } from 'vue'
import { useRoute } from 'vue-router'
const route = useRoute();
watch(() => route.params.id, (newId, oldId) => {
console.log(newId, oldId)
})
</script>
路由的匹配语法
Sensitive 与 strict 路由配置
默认情况下,所有路由是不区分大小写的,并且能匹配带有或不带有尾部斜线的路由。例如,路由
/users
将匹配/users
、/users/
、甚至/Users/
。使用Sensitive
与strict
配置后路由匹配将变为严格模式,要求路由路径必须精确匹配。
Sensitive 适用于当前配置的路由。
strict 适用于所有路由。
const router = createRouter({
history: createWebHistory(),
routes: [
{ path: '/about', sensitive: true }
],
strict: true
})
可选参数
*
和?
标志着一个参数是可选的,但?
修饰符最多只能有一个,*
无限制。
const routes: [
{ path: '/user/:id?' },
{ path: '/user/:id*/:id2*' }
]
可重复的参数
*
和+
标志参数是可重复。
const routes: [
{ path: '/user/:id+' },
{ path: '/user/:id*' }
]
// 在页面上传参 -- url地址:http://localhost:8080/user/1/2/3/4,获取到的params.id是一个数组。
<router-link :to="{ name: 'user', params: { id: [1,2,3,4] } }">User</router-link>
编程式导航
router-link
// 1.不带参数
<router-link :to="{ name: 'home' }">About</router-link>
<router-link :to="{ path: '/' }">About</router-link>
// 2.params参数(类似于post)
<router-link :to="{ name: 'user', params: { id: 123 } }">User</router-link>
// 取参
<script setup>
import { useRoute } from 'vue-router'
const route = useRoute();
const params = route.params;
</script>
// 3.query参数(类似get)
<router-link :to="{ name: 'about', query: { msg: 'name' } }">About</router-link>
<router-link :to="{ path: '/about', query: { msg: 'path' } }">About</router-link>
// 取参
<script setup>
import { useRoute } from 'vue-router'
const route = useRoute();
const puery = route.query;
</script>
router.push()
<script setup>
import { useRouter } from 'vue-router'
const router = useRouter();
</script>
// 1.不带参数
<button @click="() => { router.push('/') }">不带参数1</button>
<button @click="() => { router.push({ name: 'home' }) }">不带参数2</button>
<button @click="() => { router.push({ path: '/' }) }">不带参数3</button>
// 2.params传参
<button @click="() => { router.push({ name: 'user', params: { id: 123 } }) }">User</button>
// 3.query传参
<button @click="() => { router.push({ name: 'about', query: { msg: 'name' } }) }">About</button>
<button @click="() => { router.push({ path: '/about', query: { msg: 'path' } }) }">About</button>
router.replace()
<script setup>
import { useRouter } from 'vue-router'
const router = useRouter();
</script>
// 1.不带参数
<button @click="() => { router.replace('/') }">不带参数1</button>
<button @click="() => { router.replace({ name: 'home' }) }">不带参数2</button>
<button @click="() => { router.replace({ path: '/' }) }">不带参数3</button>
// 2.params传参
<button @click="() => { router.replace({ name: 'user', params: { id: 123 } }) }">User</button>
// 3.query传参
<button @click="() => { router.replace({ name: 'about', query: { msg: 'name' } }) }">About</button>
<button @click="() => { router.replace({ path: '/about', query: { msg: 'path' } }) }">About</button>
router.go(n)
<script setup>
import { useRouter } from 'vue-router'
const router = useRouter();
</script>
<button @click="router.go(-1)">后退一步记录,等同于 history.back()</button>
<button @click="router.go(1)">在浏览器记录中前进一步,等同于 history.forward()</button>
query 和 params 区别
query 类似get
, 跳转之后页面url
后面会拼接参数,类似?msg=name
。
params 类似post
, 跳转之后页面url
后面不会拼接参数, 但是刷新页面id会消失。
router.push()、 router.replace()、 router.go(n)三者的区别?
push:跳转到指定url路径,并向history栈中添加一个记录,点击后退会返回到上一个页面。
replace:跳转到指定url路径,但是history栈中不会有记录,点击返回会跳转到上个页面 (直接替换当前页面)。
go(n):向前或者向后跳转n个页面,n可为正整数或负整数。
嵌套路由
以
/
开头的嵌套路径将被视为根路径。
const routes = [{
path: '/news', name: 'news', component: News, children: [
{ path: 'newsList', name: 'newsList', component: NewsList },
{ path: 'newsOther', name: 'newsOther', component: NewsOther }
]
}]
命名视图
有时候想同时 (同级) 展示多个视图,而不是嵌套展示,可以在界面中拥有多个单独命名的视图。如果
router-view
没有设置名字,那么默认为default
。
const routes = [
{
path: '/', name: 'home', components: {
default: HomeView,
News,
NewsList
}
}
]
<template><router-view></router-view>
<router-view name="News"></router-view>
<router-view name="NewsList"></router-view>
</template>
重定向和别名
重定向
重定向是通过routes
配置中的redirect
字段来实现的。当路由匹配到某个路径时,可以自动重定向到另一个路径。
,当访问根路径/
时,路由会自动重定向到/home
。
// 字符串
const routes = [{ path: '/home', redirect: '/' }]
// 命名路由
const routes = [{ path: '/home', redirect: { name: 'homepage' } }]
// 方法,动态返回重定向目标 -- 1.接收目标路由作为参数 2.return重定向的字符串路径/路径对象
const routes = [
{
path: '/search/:searchText',
redirect: to => {
return { path: '/search', query: { q: to.params.searchText } }
}
}
]
相对重定向
const routes = [
{
// 将总是把/users/123/posts重定向到/users/123/profile。
path: '/users/:id/posts',
redirect: to => {
// 该函数接收目标路由作为参数
// 相对位置不以`/`开头
// 或 { path: 'profile'}
return 'profile'
}
}
]
别名
将/
别名为/home
,意味着当用户访问/home
时,URL 仍然是/home
,但会被匹配为用户正在访问/
。
// 当访问 /homeAlias 时会导航到 / 路径。
const routes = [{ path: '/', component: Homepage, alias: '/homeAlias' }]
// 当路由有参数时 -- 当访问 /u1/:id 或者 /u2/:id 时会导航到 /user/:id 路径。
{ path: '/user/:id', name: 'user',alias: ['/u1/:id','/u2/:id'], component: User }
路由组件传参
在组件中使用
$route
或useRoute()
会与路由紧密耦合,这限制了组件的灵活性,因为它只能用于特定的 URL。虽然这不一定是件坏事,但可以通过props
配置来解除这种行为。
props
有三种类型:boolean
|object
|function
。
尽可能保持 props 函数为无状态的,因为它只会在路由发生变化时起作用。如果你需要状态来定义 props,请使用包装组件,这样 vue 才可以对状态变化做出反应。
// boolean
const routes = [ { path: '/user/:id', name: 'user', props: true } ] // boolean
// object -- 对于有命名视图的路由,必须为每个命名视图定义 props 配置
const routes = [
{
path: '/user/:id',
components: { default: User, sidebar: Sidebar },
props: { default: true, sidebar: false }
}
]
// function
const routes = [
{
path: '/news',
component: News,
props: route => ({ query: route.query.text })
}
]
<script setup>
defineProps({
id: String
})
</script>
<template>
<div>User {{ id }}</div>
</template>