学习目标:
根据vue-router官网简洁的总结vue-router中的基础知识点,进阶版将会在下一篇文章中发布
动态路由匹配:
routes: [
// 动态路径参数 以冒号开头
{ path: '/user/:id', component: User }
]
像 /user/foo 和 /user/bar 都将映射到相同的路由。路径参数用:做标记,可以用this.$route.params获取,例如"user/123",获取的params为{id:123},
会出现的问题:如果两个路由映射的是同一个组件的话,vue会就地服用,也就是说该组件的vue实例不会更新,那么自然而然的生命周期函数不会重新执行
捕获所有路由:
此方法可以用来设置404界面,通过通配符*来匹配所有未命中的路由来到指定页面。
{
// 会匹配所有路径
path: '*'
}
{
// 会匹配以 `/user-` 开头的任意路径
path: '/user-*'
}
但是值得注意的是 当使用通配符路由时,请确保路由的顺序是正确的,也就是说含有通配符的路由应该放在最后。路由 { path: ‘*’ } 通常用于客户端 404 错误。
当使用一个通配符时,$route.params 内会自动添加一个名为 pathMatch 参数。它包含了 URL 通过通配符被匹配的部分:
// 给出一个路由 { path: '/user-*' }
this.$router.push('/user-admin')
this.$route.params.pathMatch // 'admin'
// 给出一个路由 { path: '*' }
this.$router.push('/non-existing')
this.$route.params.pathMatch // '/non-existing'
匹配优先级
有时候,同一个路径可以匹配多个路由,此时,匹配的优先级就按照路由的定义顺序:谁先定义的,谁的优先级就最高。
嵌套路由:
/user/foo/profile /user/foo/posts
+------------------+ +-----------------+
| User | | User |
| +--------------+ | | +-------------+ |
| | Profile | | +------------> | | Posts | |
| | | | | | | |
| +--------------+ | | +-------------+ |
+------------------+ +-----------------+
router-view可以在任意组件中使用,通过配置route的children属性,来达到这种关系
列如
我们在app组件中使用了router-view
<div id="app">
<router-view></router-view>
</div>
const User = {
template: '<div>User {{ $route.params.id }}</div>'
}
const router = new VueRouter({
routes: [
{ path: '/user/:id', component: User }
]
})
我们在User组件也想使用router-view,在User组件内部做路由跳转,那么这种关系如何来描述让vue懂我们的意思呢?使用children属性,提供一个空的子路由来在未匹配到任何children的时候显示
const router = new VueRouter({
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
},
// 当 /user/:id 匹配成功,
// UserHome 会被渲染在 User 的 <router-view> 中
{ path: '', component: UserHome },
]
}
]
})
编程式导航和声明式导航
编程式导航是this.$router.push这种,声明式是<router-link :to="…">这种
router.push方法是往浏览器记录栈中添加一条记录,当你点击<router-link>的时候,会在内部调用router.push方法,所以实际上是一样的
// 字符串
router.push('home')
// 对象
router.push({ path: 'home' })
// 命名的路由,params会被忽略
router.push({ name: 'user', params: { userId: '123' }})
// 带查询参数,变成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})
注意:如果提供了path,params会被忽略,意思是path不能跟params一起使用,解决方法如下
const userId = '123'
router.push({ name: 'user', params: { userId }}) // -> /user/123
router.push({ path: `/user/${userId}` }) // -> /user/123
// 这里的 params 不生效
router.push({ path: '/user', params: { userId }}) // -> /user
router.replace()跟router.push很像,只不过不会再浏览器记录栈中添加记录
router,go()浏览器前进后退
你也许注意到 router.push、router.replac 和 router.gowindow.history.pushState、 window.history.replaceState 和 window.history.go好像, 实际上它们确实是效仿 window.history API 的。因此,如果你已经熟悉 Browser History APIs,那么在 Vue Router 中操作 history 就是超级简单的。还有值得提及的,Vue Router 的导航方法 (push、 replace、 go) 在各类路由模式 (history、 hash 和 abstract) 下表现一致
命名路由
可以在配置的时候加上name属性
const router = new VueRouter({
routes: [
{
path: '/user/:userId',
name: 'user',
component: User
}
]
})
通过name进行路由跳转,跟path跳转的时候差不多一个效果,不过用path的时候Params会被忽略,所以用name跳转。
router.push({ name: 'user', params: { userId: 123 }})
命名视图
上面提到了嵌套路由,但是嵌套路由是在一个组件中只有一个router-view中可以,那如果一个组件中需要用多种router-view呢?那么命名视图就派上了用场,实际上就是在router-view上加上name属性,我心思在组件里引入你需要的组件写上不一个效果吗,但是用命名视图的这种方式在很多页面都有相同布局的时候,会比较常用(个人理解),手动狗头
<router-view class="view one"></router-view>
<router-view class="view two" name="a"></router-view>
<router-view class="view three" name="b"></router-view>
同时在routes中进行配置,默认是default注意这里用的是components,而不是之前的component
const router = new VueRouter({
routes: [
{
path: '/',
components: {
default: Foo,
a: Bar,
b: Baz
}
}
]
})
重定向和别名
const router = new VueRouter({
routes: [
{ path: '/a', redirect: '/b' }
]
})
重定向的目标也可以是命名路由
const router = new VueRouter({
routes: [
{ path: '/a', redirect: { name: 'foo' }}
]
})
甚至是一个方法,动态返回重定向目标:
const router = new VueRouter({
routes: [
{ path: '/a', redirect: to => {
// 方法接收 目标路由 作为参数
// return 重定向的 字符串路径/路径对象
}}
]
})
注意:重定向上的routes如果配置了beforeEnter那么/a不会有任何效果,因为导航首位只到目标路由上。
别名
/a 的别名是 /b,意味着,当用户访问 /b 时,URL 会保持为 /b,但是路由匹配则为 /a,就像用户访问 /a 一样。
“别名”的功能让你可以自由地将 UI 结构映射到任意的 URL,而不是受限于配置的嵌套路由结构。
const router = new VueRouter({
routes: [
{ path: '/a', component: A, alias: '/b' }
]
})
路由组件传参
在我们使用组件的时候,在模板上可能用过{{this.$route.params.id}}这种方式来渲染模板,但这样就会让路由跟对应组件高度耦合,也就是说该组件只能当路由组件用。
const User = {
template: '<div>User {{ $route.params.id }}</div>'
}
const router = new VueRouter({
routes: [
{ path: '/user/:id', component: User }
]
})
通过props解耦,让组件可以当普通的组件传递Props那样使用也可以当路由组件使用。
const User = {
props: ['id'],
template: '<div>User {{ id }}</div>'
}
const router = new VueRouter({
routes: [
{ path: '/user/:id', component: User, props: true },
// 对于包含命名视图的路由,你必须分别为每个命名视图添加 `props` 选项:
{
path: '/user/:id',
components: { default: User, sidebar: Sidebar },
props: { default: true, sidebar: false }
}
]
})
这样你便可以在任何地方使用该组件,使得该组件更易于重用和测试。
布尔模式
如果 props 被设置为 true,route.params 将会被设置为组件属性。
对象模式
如果 props 是一个对象,它会被按原样设置为组件属性。当 props 是静态的时候有用。如果不是静态的用下面的函数模式。
const router = new VueRouter({
routes: [
{ path: '/promotion/from-newsletter', component: Promotion, props: { newsletterPopup: false } }
]
})
函数模式
你可以创建一个函数返回 props。这样你便可以将参数转换成另一种类型,将静态值与基于路由的值结合等等。总之这几种方式都是将路由的参数设置为Props,将路由跟对应的视图组件解耦,就不用在created或者mounted里在进行赋值啥的,比如:this.data=this.$route.query.data
const router = new VueRouter({
routes: [
{ path: '/search', component: SearchUser, props: (route) => ({ query: route.query.q }) }
]
})
History 模式
vue-router默认的路由模式是hash模式,是通过’#‘号后面来模拟url来实现路由跳转的,#后面的参数变化页面不会重新加载。
还有一种方式就是通过history方式,他是通过浏览器提供的history.pushState API来实现路由的跳转,它不像hash一样有’#'号,路径就是真实的路径,但是调用api时,不会触发浏览器加载,但是当你刷新浏览器的时候,hash值是不会当作path来发请求的,但是history是实打实的路径,它会带上,那么这时候你后端如果没有处理,命中不到相关资源那么就会404了,所以这里需要处理一下。如果后端没有命中f任何静态资源,那么返回根路径下的静态html。
const router = new VueRouter({
mode: 'history',
routes: [...]
})
举个nginx的例子,这应该是最常用的了吧,别的例子官网有
location / {
try_files $uri $uri/ /index.html;
}
如果这样写了,那么你的服务器就永远不会返回404了,所以后端处理没匹配到的路径统一返回静态资源,前端处理没有命中的Path返回404页面,也就是上面提到的用通配符*号来做这种处理,记得要放在最后面,因为优先级是按照你写的顺序来的。
const router = new VueRouter({
mode: 'history',
routes: [
{ path: '*', component: NotFoundComponent }
]
})
总结
以上是就vue-router总结的基础资料,不过还是建议去看官网,因为这是个人的笔记,有一些地方本人会省略。