一、基础入门
1.1入门
首先我们要知道两个标签 一个是 router-link(入口和router-view(出口)。
<div id="app">
<h1>Hello App!</h1>
<p>
<!--使用 router-link 组件进行导航 -->
<!--通过传递 `to` 来指定链接 -->
<!--`<router-link>` 将呈现一个带有正确 `href` 属性的 `<a>` 标签-->
<router-link to="/">Go to Home</router-link>
<router-link to="/about">Go to About</router-link>
</p>
<!-- 路由出口 -->
<!-- 路由匹配到的组件将渲染在这里 -->
<router-view></router-view>
</div>
1.2 使用步骤
// 1. 定义路由组件.
// 也可以从其他文件导入
const Home = { template: '<div>Home</div>' }
const About = { template: '<div>About</div>' }
// 2. 定义一些路由
// 每个路由都需要映射到一个组件。
// 我们后面再讨论嵌套路由。
const routes = [
{ path: '/', component: Home },
{ path: '/about', component: About },
]
// 3. 创建路由实例并传递 `routes` 配置
// 你可以在这里输入更多的配置,但我们在这里
// 暂时保持简单
const router = VueRouter.createRouter({
// 4. 内部提供了 history 模式的实现。为了简单起见,我们在这里使用 hash 模式。
history: VueRouter.createWebHashHistory(),
routes, // `routes: routes` 的缩写
})
// 5. 创建并挂载根实例
const app = Vue.createApp({})
//确保 _use_ 路由实例使
//整个应用支持路由。
app.use(router)
app.mount('#app')
// 现在,应用已经启动了!
通过调用 app.use(router)
,我们会触发第一次导航且可以在任意组件中以 this.$router
的形式访问它,并且以 this.$route
的形式访问当前路由:
// Home.vue
export default {
computed: {
username() {
// 我们很快就会看到 `params` 是什么
return this.$route.params.username
},
},
methods: {
goToDashboard() {
if (isAuthenticated) {
this.$router.push('/dashboard')
} else {
this.$router.push('/login')
}
},
},
}
要在 setup
函数中访问路由,因为没有this 所以请调用 useRouter
或 useRoute
函数。
二、动态路由匹配
2.1 带参数的动态路由匹配
const User = {
template: '<div>User</div>',
}
// 这些都会传递给 `createRouter`
const routes = [
// 动态字段以冒号开始
{ path: '/users/:id', component: User },
]
其中的id 就是路由参数 /users/1 和 /users/2 这样的URL 都会映射到同一个路由。
路径参数 用冒号 : 表示 当一个路由匹配时,他的params的值将在每一个组件中以 this.$route.params 的形式暴露出来 因为 我们可以这样访问到:
const User = {
template: '<div>User {{ $route.params.id }}</div>',
}
我们也可以在同一个路由设置多个路径参数 都会映射在 $route.params上:
/users/:username/posts/:postId====>/users/eduardo/posts/123===>{ username: 'eduardo', postId: '123' } |
除了 $route.params
之外,$route
对象还公开了其他有用的信息,如 $route.query
(如果 URL 中存在参数)、$route.hash
等
2.2 响应路由参数的变化
当携带有路由参数的时候 说明这个路由可能会被复用 因为都是渲染同一个组件 比起销毁在创建 复用更高效 不过这也意味着组件的生命周期钩子不会被调用 所以要对同一个组件的参数变化做出响应 你可以简单地watch $route 对象上的任意属性 在这个场景下 就是 $route.params:
const User = {
template: '...',
created() {
this.$watch(
() => this.$route.params,
(toParams, previousParams) => {
// 对路由变化做出响应...
}
)
},
}
或者,使用 beforeRouteUpdate
导航守卫,它也可以取消导航:
const User = {
template: '...',
async beforeRouteUpdate(to, from) {
// 对路由变化做出响应...
this.userData = await fetchUser(to.params.id)
},
}
三、路由的匹配语法
3.1在参数中自定义正则
当我们在路由路径上匹配的时候 有两个路由 /:orderId 和 /:productName,两者会匹配完全相同的URL,那么我们需要区分他们 最简单的方式 就是在路径起那么添加一个静态部分来区分:
const routes = [
// 匹配 /o/3549
{ path: '/o/:orderId' },
// 匹配 /p/books
{ path: '/p/:productName' },
]
但是又比如说 我们不想用这种方式 毕竟这种方式会让地址变得不好看 而且orderId总是一个数字 而 productName 可以是任何东西 所以我们可以在括号中为参数指定一个自定义的正则:
const routes = [
// /:orderId -> 仅匹配数字
{ path: '/:orderId(\\d+)' },
// /:productName -> 匹配其他任何内容
{ path: '/:productName' },
]
如果是 /25将匹配到 ‘/:orderId’,其他情况将会匹配 /:productName, route数组顺序并不重要。
3.2可重复的参数
如果你需要匹配具有多个部分的路由,如 /first/second/third
,你应该用 *
(0 个或多个)和 +
(1 个或多个)将参数标记为可重复:
const routes = [
// /:chapters -> 匹配 /one, /one/two, /one/two/three, 等
{ path: '/:chapters+' },
// /:chapters -> 匹配 /, /one, /one/two, /one/two/three, 等
{ path: '/:chapters*' },
]
这将为你提供一个参数数组,而不是一个字符串,并且在使用命名路由时也需要你传递一个数组:
// 给定 { path: '/:chapters*', name: 'chapters' },
router.resolve({ name: 'chapters', params: { chapters: [] } }).href
// 产生 /
router.resolve({ name: 'chapters', params: { chapters: ['a', 'b'] } }).href
// 产生 /a/b
// 给定 { path: '/:chapters+', name: 'chapters' },
router.resolve({ name: 'chapters', params: { chapters: [] } }).href
// 抛出错误,因为 `chapters` 为空
四、嵌套路由
4.1 用法
当我们在app文件里写了一个路由出口 route-view 作为最顶层的 它渲染顶层路由匹配的组件。同样的 一个被渲染的组件也可以包含自己嵌套的<router-view>;然后我们需要在路由中配置children。
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,
},
],
},
]
注意,以 /
开头的嵌套路径将被视为根路径。这允许你利用组件嵌套,而不必使用嵌套的 URL。
五、编程式导航
5.1 导航到不同的位置
在vue实例中 我们可以通过$router 访问路由实例 所以可以调用this.$router.push 这个方法可以跳转到你想去的路由 会向history栈添加一条新的记录 所以用户点击浏览器后退 会回到之前的URL。
// 字符串路径
router.push('/users/eduardo')
// 带有路径的对象
router.push({ path: '/users/eduardo' })
// 命名的路由,并加上参数,让路由建立 url
router.push({ name: 'user', params: { username: 'eduardo' } })
// 带查询参数,结果是 /register?plan=private
router.push({ path: '/register', query: { plan: 'private' } })
// 带 hash,结果是 /about#team
router.push({ path: '/about', hash: '#team' })
注意:如果提供了 path
,params
会被忽略,上述例子中的 query
并不属于这种情况。取而代之的是下面例子的做法,你需要提供路由的 name
或手写完整的带有参数的 path
:
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
5.2 替换当前的位置
和push 唯一不同的是 它在导航时不会向history 添加新纪录 只是替换了当前的URL而已
router.push({ path: '/home', replace: true })
// 相当于
router.replace({ path: '/home' })
5.3 横跨历史
该方法采用一个整数作为参数,表示在历史堆栈中前进或后退多少步,类似于 window.history.go(n)
。
// 向前移动一条记录,与 router.forward() 相同
router.go(1)
// 返回一条记录,与 router.back() 相同
router.go(-1)
// 前进 3 条记录
router.go(3)
// 如果没有那么多记录,静默失败
router.go(-100)
router.go(100)
六、命名路由
6.1 用法
除了path之外 我们还可以给任何路由提供一个name 属性
没有硬编码的URL ;params的自动编码/解码; 防止你在URL中出现打字错误 ;绕过路径排序
const routes = [
{
path: '/user/:username',
name: 'user',
component: User,
},
]
//要链接到一个命名的路由,可以向 router-link 组件的 to 属性传递一个对象
<router-link :to="{ name: 'user', params: { username: 'erina' }}">
User
</router-link>
//这个和push是一回事
router.push({ name: 'user', params: { username: 'erina' } })