共计 4903 个字符,预计需要花费 13 分钟才能阅读完成。
入门
用 Vue + Vue Router 创立单页利用非常简单:通过 Vue.js,曾经用组件组成了利用。当退出 Vue Router 时,将组件映射到路由上,让 Vue Router 晓得在哪里渲染它们。
HTML
<script src="https://unpkg.com/vue@3"></script>
<script src="https://unpkg.com/vue-router@4"></script>
<div id="app">
<h1>Hello App!</h1>
<p>
<router-link to="/">Go to Home</router-link>
<router-link to="/about">Go to About</router-link>
</p>
<router-view></router-view>
</div>
router-link
在这里没有应用惯例的 a 标签,而是应用一个自定义组件 router-link 来创立链接。这使得 Vue Router 能够在不从新加载页面的状况下更改 URL,解决 URL 的生成以及编码。
router-view
router-view 显示与 url 对应的组件。能够把它放在任何中央,以适应你的布局。
JavaScript
const Home = {template: '<div>Home</div>'}
const About = {template: '<div>About</div>'}
const routes = [{ path: '/', component: Home},
{path: '/about', component: About},
]
const router = VueRouter.createRouter({history: VueRouter.createWebHashHistory(),
routes, // `routes: routes` 的缩写
})
const app = Vue.createApp({})
app.use(router)
app.mount('#app')
通过调用 app.use(router),能够在任意组件中以 this.$router 的模式拜访它,并且以 this.$route 的模式拜访以后路由:
带参数的动静路由匹配
很多时候,须要将给定匹配模式的路由映射到同一个组件。在 Vue Router 中,能够在门路中应用一个动静字段来实现,称之为 门路参数:
const User = {template: '<div>User</div>',}
// 这些都会传递给 `createRouter`
const routes = [
// 动静字段以冒号开始
{path: '/users/:id', component: User},
]
当初像 /users/johnny 和 /users/jolyne 这样的 URL 都会映射到同一个路由。门路参数 用冒号 : 示意。
响应路由参数的变动
应用带有参数的路由时须要留神,当你从 /users/johnny 导航到 /users/jolyne 时,雷同的组件实例将被重复使用。因为两个路由都渲染同个组件,比起销毁再建,复用则显得更加高效。不过,这也意味着组件的生命周期钩子不会被调用。
要对同一个组件中参数的变动做出响应的话,能够简略地 watch $route 对象上的任意属性,在这个场景中,就是 $route.params:
const User = {
template: '...',
created() {
this.$watch(() => this.$route.params,
(toParams, previousParams) => {// 对路由变动做出响应...}
)
},
}
路由的匹配语法
大多数利用都会应用 /about 这样的动态路由和 /users/:userId 这样的动静路由,就像方才在动静路由匹配中看到的那样,然而 Vue Router 能够提供更多的形式!
在参数中自定义正则
当定义像 :userId 这样的参数时,外部应用以下的正则 (如 [ ^ /]+) (至多有一个字符不是 /) 来从 URL 中提取参数。当你须要依据参数的内容来辨别两个路由,最简略的办法就是在门路中增加一个动态局部来辨别它们:
const routes = [
// 匹配 /o/3549
{path: '/o/:orderId'},
// 匹配 /p/books
{path: '/p/:productName'},
]
但在某些状况下,不想增加动态的 /o /p 局部。因为,orderId 总是一个数字,而 productName 能够是任何货色,所以能够在括号中为参数指定一个自定义的正则:
const routes = [
// /:orderId -> 仅匹配数字
{path: '/:orderId(\\d+)' },
// /:productName -> 匹配其余任何内容
{path: '/:productName'},
]
当初,转到 /25 将匹配 /:orderId,其余状况将会匹配 /:productName。routes 数组的程序并不重要!
可反复的参数
如果须要匹配具备多个局部的路由,如 /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*'},
]
这将会提供一个参数数组,而不是一个字符串,并且在应用命名路由时也须要传递一个数组:
可选参数
能够通过应用 ? 修饰符 (0 个或 1 个) 将一个参数标记为可选
const routes = [
// 匹配 /users 和 /users/posva
{path: '/users/:userId?'},
// 匹配 /users 和 /users/42
{path: '/users/:userId(\\d+)?' },
]
这里须要留神,* 在技术上也标记着一个参数是可选的,但 ? 参数不能反复。
调试
如果要探索路由是如何转化为正则的,以理解为什么一个路由没有被匹配,或者,报告一个 bug,能够应用门路排名工具。它反对通过 URL 分享路由。
嵌套路由
一些应用程序的 UI 由多层嵌套的组件组成。在这种状况下,URL 的片段通常对应于特定的嵌套组件构造,例如:
/user/johnny/profile /user/johnny/posts
+------------------+ +-----------------+
| User | | User |
| +--------------+ | | +-------------+ |
| | Profile | | +------------> | | Posts | |
| | | | | | | |
| +--------------+ | | +-------------+ |
+------------------+ +-----------------+
通过 Vue Router,能够应用嵌套路由配置来表白这种关系。
<div id="app">
<router-view></router-view>
</div>
const User = {template: '<div>User {{ $route.params.id}}</div>',
}
// 这些都会传递给 `createRouter`
const routes = [{path: '/user/:id', component: User}]
这里的 <router-view> 是一个顶层的 router-view。它渲染顶层路由匹配的组件。同样地,一个被渲染的组件也能够蕴含本人嵌套的 <router-view>。如果在 User 组件的模板内增加一个 <router-view>:
const User = {
template: `
<div class="user">
<h2>User {{$route.params.id}}</h2>
<router-view></router-view>
</div>
`,
}
要将组件渲染到这个嵌套的 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。
如你所见,children 配置只是另一个路由数组,就像 routes 自身一样。因而,你能够依据本人的须要,一直地嵌套视图。
编程式导航
除了应用 <router-link> 创立 a 标签来定义导航链接,还能够借助 router 的实例办法,通过编写代码来实现。
导航到不同的地位
想要导航到不同的 URL,能够应用 router.push 办法。这个办法会向 history 栈增加一个新的记录,所以,当用户点击浏览器后退按钮时,会回到之前的 URL。
当点击 <router-link> 时,外部会调用这个办法,所以点击 <router-link :to=”…”> 相当于调用 router.push(…):
该办法的参数能够是一个字符串门路,或者一个形容地址的对象。
// 字符串门路
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
因为属性 to 与 router.push 承受的对象品种雷同,所以两者的规定完全相同。
router.push 和所有其余导航办法都会返回一个 Promise,让咱们能够等到导航实现后才晓得是胜利还是失败。
替换以后地位
它的作用相似于 router.push,惟一不同的是,它在导航时不会向 history 增加新记录,正如它的名字所暗示的那样——它取代了以后的条目。
也能够间接在传递给 router.push 的 routeLocation 中减少一个属性 replace: true:
router.push({path: '/home', replace: true})
// 相当于
router.replace({path: '/home'})