vue-router
实际上是封装了h5
的history
的api
。
1. active-class
选中的router-link
将自动添加一个class
属性值.router-link-active
,可以让active
的导航高亮等等。
<router-link tag="div" class="tab-item" to="recommend">
<span class="tab-link">推荐</span>
</router-link>
stylus方式
第一种
配置
new Router({
linkActiveClass: 'active'
})
css
.tab-item
flex: 1
text-align: center
.tab-link
padding-bottom: 5px
color: $color-text-l
&.active
.tab-link
color: $color-theme
border-bottom: 2px solid $color-theme
第二种:直接css
.tab-item
flex: 1
text-align: center
.tab-link
padding-bottom: 5px
color: $color-text-l
&.router-link-active
.tab-link
color: $color-theme
border-bottom: 2px solid $color-theme
2.路由懒加载
当打包构建应用时,Javascript
包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。
异步组件
2.1 常用方式
webpack
已经将require.ensure
用import
取代
const router = new VueRouter({
routes: [
path: '/app',
component: () => import('./app'), // 引入组件
]
})
或者
const app = () => import('./app')
const router = new VueRouter({
routes: [
path: '/app',
component: app, // 引入组件
]
})
懒加载前
懒加载后
2.2 组件按组分块
有时候我们想把某个路由下的所有组件都打包在同个异步块(chunk)
中。
只需要使用 命名 chunk
,一个特殊的注释语法来提供 chunk name
(需要 Webpack > 2.4
)
const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')
const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue')
const Baz = () => import(/* webpackChunkName: "group-foo" */ './Baz.vue')
Webpack
会将任何一个异步模块与相同的块名称组合到相同的异步块中。
3.路由传参
在组件中使用 $route
会使之与其对应路由形成高度耦合,从而使组件只能在某些特定的URL
上使用,限制了其灵活性。
使用 props
将组件和路由解耦:
3.1 取代与 $route 的耦合
const User = {
template: '<div>User {{ $route.params.id }}</div>'
}
const router = new VueRouter({
routes: [
{ path: '/user/:id', component: User }
]
})
3.2 通过 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 }
}
]
})
4. HTML5 History 模式
4.1 hash模式
vue-router
默认hash
模式 —— 使用 URL
的hash
来模拟一个完整的URL
,于是当 URL
改变时,页面不会重新加载
4.2 history模式(重点)
如果不想要很丑的hash
,我们可以用路由的 history
模式,这种模式充分利用history.pushState API
来完成 URL
跳转而无须重新加载页面。
history
模式中也有可以实现前进、后退以及跳转,但是遇到F5
(刷新)就挂了,因为刷新是实实在在地去请求服务器的。hash
模式只是修改#
中的内容,而浏览器请求是不带它玩的,所以没什么问题- 但是在
history
模式中,我们可以自由的修改path
,当刷新时,如果服务器中没有相应的响应或者资源,分分钟刷出一个404!!!
const router = new VueRouter({
mode: 'history',
routes: [...]
})
当你使用history
模式时,URL
就像正常的url
,例如http://yoursite.com/user/id
,也好看!
不过这种模式要玩好,还需要后台配置支持。因为我们的应用是个单页客户端应用,如果后台没有正确的配置,当用户在浏览器直接访问http://oursite.com/user/id
就会返回 404,这就不好看了。
所以呢,你要在服务端增加一个覆盖所有情况的候选资源:如果URL
匹配不到任何静态资源,则应该返回同一个 index.html
页面,这个页面就是你 app
依赖的页面。
vue-router history模式下,后台配置
node + express
的配置,结合插件connect-history-api-fallback
:
var history = require('connect-history-api-fallback');
app.use(history({
htmlAcceptHeaders: ['text/html', 'application/xhtml+xml'],
rewrites: [{
from: /^\/.*$/,
to: function (context) {
return "/";
}
}, ]
}));
app.use(express.static(path.join(__dirname, 'public')));
5.命名视图
有时候想同时 (同级) 展示多个视图,而不是嵌套展示,例如创建一个布局:
注意:
- 一个视图使用一个组件渲染,因此对于同个路由,多个视图就需要多个组件。确保正确使用 components 配置 (带上 s)。
- 如果
router-view
没有设置名字,那么默认为default
。
6. 命名路由
在routes
配置中给某个路由设置名称。
const router = new VueRouter({
routes: [
{
path: '/user/:userId',
name: 'user',
component: User
}
]
})
要链接到一个命名路由,可以给 router-link
的 to
属性传一个对象:
to的写法:to
<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>
这跟代码调用router.push()
是一回事:
router.push({ name: 'user', params: { userId: 123 }})
这两种方式都会把路由导航到/user/123
路径。
7.嵌套路由
-
填写
children
子路由的path
不要加/
-
在
to
后面写路由路径的时候,一定到带上绝对路径,也就是要把pages
这个父路由路径写进去"/pages/movie"
<router-link to="/pages/movie">影院热映</router-link> 注意— to不加:
-
等价使用命名路由
<router-link :to="{name: 'MovieView'}">影院热映</router-link> 注意— to加:
-
渲染到
html
的结果
8.router-link
<!-- 字符串 -->
<router-link to="home">Home</router-link>
<!-- 渲染结果 -->
<a href="home">Home</a>
<!-- 使用 v-bind 的 JS 表达式 -->
<router-link v-bind:to="'home'">Home</router-link>
<!-- 不写 v-bind 也可以,就像绑定别的属性一样 -->
<router-link :to="'home'">Home</router-link>
<!-- 同上 -->
<router-link :to="{ path: 'home' }">Home</router-link>
<!-- 命名的路由 -->
<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>
<!-- 带查询参数,下面的结果为 /register?plan=private -->
<router-link :to="{ path: 'register', query: { plan: 'private' }}">Register</router-link>
9. path
vue-router中path写 / 和 /* 有什么区别:
假如你的项目运行在
http://127.0.0.1:8080
那么/
匹配的是http://127.0.0.1:8080/
而/*
可以匹配http://127.0.0.1:8080/home、http://127.0.0.1:8080/main、http://127.0.0.1:8080/other
等其他路由
10. bug
bug1: 路由传参数
路径中要特殊符号/
等要转义
/user/124 <div>User 123 </div>
/user/http:%2F%2Flocalhost:9999 <div>User http://localhost:9999</div>
11. query 与 params 的使用和区别
11.1 query的使用
带查询参数,变成 /register?plan=private
router.push({ path: 'register', query: {plan: 'private'}})
11.2 params的配置和调用
路由配置,使用params
传参数,使用name
{
path: '/detail/:id',
name: 'detail',
component: Detail,
}
调用this.$router.push
进行params
传参,使用name
,前提需要在路由配置里设置过:路由名称。
this.$router.push({
name: 'detail',
params: {
id: '2019'
}
})
params
接收参数
const { id } = this.$route.params
11.3 注意
- query通常与path使用。
query
带查询参数,params
路径参数。- 如果提供了
path
,params
会被忽略。
// params 不生效
router.push({ path: '/user', params: { userId }}) // -> /user