Vue - vue中的路由vue-router
路由模式
- Hash模式
对SEO不友好,#之后的url, 不会发送到服务器端,所以服务端无需做任何处理就可以使用。
import { createRouter, createWebHashHistory } from 'vue-router'
const router = createRouter({
history: createWebHashHistory(),
routes: [
//...
],
})
- Memory模式
非浏览器模式下的路由选择, 用在浏览器端无历史记录,需要主动触发导航.
import { createRouter, createMemoryHistory } from 'vue-router'
const router = createRouter({
history: createMemoryHistory(),
routes: [
//...
],
})
- HTML5模式(推荐)
标准的url,生产环境下,服务端需要添加简单的回退路由。
(1) 当无法匹配路由时要跳转到index.html, 否则,在浏览器地址栏直接访问url时,可能会出现404页面.
(2) 404 页面需要在前端进行配置
- 路由配置
import { createRouter, createWebHistory } from 'vue-router'
const router = createRouter({
history: createWebHistory(),
routes: [
//...
// 万能路由,配置404 NotFoundComponent
{ path: '/:pathMatch(.*)', component: NotFoundComponent }
],
})
- nginx 配置
location / {
try_files $uri $uri/ /index.html;
}
动态路由匹配
- 路由参数进行匹配
const User = {
template: '<div>User {{ $route.params.id }}</div>',
}
// 这些都会传递给 `createRouter`
const routes = [
// 动态字段以冒号开始
{ path: '/users/:id', component: User },
]
- 路由参数中自定义正则
const routes = [
// 将匹配所有内容并将其放在 `$route.params.pathMatch` 下
{ path: '/:pathMatch(.*)*', name: 'NotFound', component: NotFound },
// 将匹配以 `/user-` 开头的所有内容,并将其放在 `$route.params.afterUser` 下
{ path: '/user-:afterUser(.*)', component: UserGeneric },
]
- 匹配特殊数据
const routes = [
// /:orderId -> 仅匹配数字
{ path: '/:orderId(\\d+)' },
// /:productName -> 匹配其他任何内容
{ path: '/:productName' },
]
- 匹配重复参数
const routes = [
// /:chapters -> 匹配 /one, /one/two, /one/two/three, 等
{ path: '/:chapters+' },
// /:chapters -> 匹配 /, /one, /one/two, /one/two/three, 等
{ path: '/:chapters*' },
]
- 匹配可选参数
const routes = [
// 匹配 /users 和 /users/posva
{ path: '/users/:userId?' },
// 匹配 /users 和 /users/42
{ path: '/users/:userId(\\d+)?' },
]
嵌套路由
- 需要匹配的url
/user/johnny/profile /user/johnny/posts
+------------------+ +-----------------+
| User | | User |
| +--------------+ | | +-------------+ |
| | Profile | | +------------> | | Posts | |
| | | | | | | |
| +--------------+ | | +-------------+ |
+------------------+ +-----------------+
- 渲染的模版
const User = {
template: `
<div class="user">
<h2>User {{ $route.params.id }}</h2>
<router-view></router-view>
</div>
`,
}
- 路由配置
const routes = [
{
path: '/user/:id',
component: User,
children: [
{
// 当 /user/:id/profile 匹配成功
// UserProfile 将被渲染到 User 的 <router-view> 内部
path: 'profile',
component: UserProfile,
},
{
// 当 /user/:id/posts 匹配成功
// UserPosts 将被渲染到 User 的 <router-view> 内部
path: 'posts',
component: UserPosts,
},
],
},
]
编程式导航与声明式导航
- 声明式导航
<router-link :to="...">
<router-link :to="..." replace>
- 编程式导航
- 导航到不同位置
const username = 'eduardo'
// 我们可以手动建立 url,但我们必须自己处理编码
router.push(`/user/${username}`) // -> /user/eduardo
// 同样
router.push({ path: `/user/${username}` }) // -> /user/eduardo
// 如果可能的话,使用 `name` 和 `params` 从自动 URL 编码中获益
router.push({ name: 'user', params: { username } }) // -> /user/eduardo
// `params` 不能与 `path` 一起使用
router.push({ path: '/user', params: { username } }) // -> /user
// 带查询参数,结果是 /register?plan=private
router.push({ path: '/register', query: { plan: 'private' } })
// 带 hash,结果是 /about#team
router.push({ path: '/about', hash: '#team' })
- 替换当前位置
router.push({ path: '/home', replace: true })
// 相当于
router.replace({ path: '/home' })
- 横跨历史
// 向前移动一条记录,与 router.forward() 相同
router.go(1)
// 返回一条记录,与 router.back() 相同
router.go(-1)
// 前进 3 条记录
router.go(3)
// 如果没有那么多记录,静默失败
router.go(-100)
router.go(100)
命名路由
- 没有硬编码的 URL
- params 的自动编码/解码。
- 防止你在 url 中出现打字错误。
- 绕过路径排序(如显示一个)
const routes = [
{
path: '/user/:username',
name: 'user',
component: User,
},
]
<router-link :to="{ name: 'user', params: { username: 'erina' }}">
User
</router-link>
router.push({ name: 'user', params: { username: 'erina' } })
命名视图
在界面中拥有多个单独命名的视图,而不是只有一个单独的出口。如果 router-view 没有设置名字,那么默认为 default。
- 需要匹配的url
/settings/emails /settings/profile
+-----------------------------------+ +------------------------------+
| UserSettings | | UserSettings |
| +-----+-------------------------+ | | +-----+--------------------+ |
| | Nav | UserEmailsSubscriptions | | +------------> | | Nav | UserProfile | |
| | +-------------------------+ | | | +--------------------+ |
| | | | | | | | UserProfilePreview | |
| +-----+-------------------------+ | | +-----+--------------------+ |
+-----------------------------------+ +------------------------------+
- 视图模版
<!-- UserSettings.vue -->
<div>
<h1>User Settings</h1>
<NavBar />
<router-view />
<router-view name="helper" />
</div>
- 路由配置
{
path: '/settings',
// 你也可以在顶级路由就配置命名视图
component: UserSettings,
children: [
{
path: 'emails',
component: UserEmailsSubscriptions
},
{
path: 'profile',
components: {
default: UserProfile,
helper: UserProfilePreview
}
}
]
}
重定向和别名
- 重定向
- 字符串重定向
const routes = [{ path: '/home', redirect: '/' }]
- 命名路由重定向
const routes = [{ path: '/home', redirect: { name: 'homepage' } }]
- 使用函数重定向
const routes = [
{
// /search/screens -> /search?q=screens
path: '/search/:searchText',
redirect: to => {
// 方法接收目标路由作为参数
// return 重定向的字符串路径/路径对象
return { path: '/search', query: { q: to.params.searchText } }
},
},
{
path: '/search',
// ...
},
]
- 相对重定向
const routes = [
{
// 将总是把/users/123/posts重定向到/users/123/profile。
path: '/users/:id/posts',
redirect: to => {
// 该函数接收目标路由作为参数
// 相对位置不以`/`开头
// 或 { path: 'profile'}
return 'profile'
},
},
]
- 别名
通过别名,你可以自由地将 UI 结构映射到一个任意的 URL,而不受配置的嵌套结构的限制。使别名以 / 开头,以使嵌套路径中的路径成为绝对路径。你甚至可以将两者结合起来,用一个数组提供多个别名。 实现多个url匹配一个UI结构。
const routes = [
{
path: '/users',
component: UsersLayout,
children: [
// 为这 3 个 URL 呈现 UserList
// - /users
// - /users/list
// - /people
{ path: '', component: UserList, alias: ['/people', 'list'] },
],
},
]
const routes = [
{
path: '/users/:id',
component: UsersByIdLayout,
children: [
// 为这 3 个 URL 呈现 UserDetails
// - /users/24
// - /users/24/profile
// - /24
{ path: 'profile', component: UserDetails, alias: ['/:id', ''] },
],
},
]
将props传递到路由组件
其主要目的是,将$routes从模版中解耦
- 布尔模式
当 props 设置为 true 时,route.params 将被设置为组件的 props。
const User = {
// 请确保添加一个与路由参数完全相同的 prop 名
props: ['id'],
template: '<div>User {{ id }}</div>'
}
const routes = [{ path: '/user/:id', component: User, props: true }]