用 Vue + Vue Router 创建单页应用非常简单:通过 Vue.js,我们已经用组件组成了我们的应用。当加入 Vue Router 时,需要做的就是将我们的组件映射到路由上,让 Vue Router 知道在哪里渲染它们。
<div id="app">
<h1>Hello App!</h1>
<p>
<!--使用 router-link 组件进行导航 -->
<!--通过传递 `to` 来指定链接,相当于 `href` -->
<!-- <router-link> 将呈现一个带有正确 `href` 属性的 <a> 标签 -->
<router-link to="/">首页</router-link>
<router-link to="/about">About组件</router-link>
</p>
<!-- 路由出口:路由匹配到的组件将渲染在这里 -->
<router-view></router-view>
</div>
没有使用常规的 a 标签,而是使用一个自定义组件 router-link 来创建链接。这使得 Vue Router 可以在不重新加载页面的情况下更改 URL,处理 URL 的生成以及编码。
将显示与 url 对应的组件。可以把它放在任何地方,以适应你的布局。
index.js:
import Vue from 'vue'
// 1.引入vue-router
import Router from 'vue-router'
// 2.定义或引入路由组件
const Home = { template: '首页' }
import About from '@/pages/About'
Vue.use(Router)
// 3. 创建路由实例并传递 routes 配置
export default new Router({
// 4.定义路由:每个路由都需要映射到一个组件
routes: [
{
path: '/',
name: 'Home',
component: Home
}, {
path: '/about',
name: 'About',
component: About
}
]
})
main.js:
// 5.创建并挂载根实例
import Vue from 'vue'
import App from './App'
import router from './router'
Vue.config.productionTip = false
new Vue({
el: '#app',
router,
components: { App },
template: ' '
})
可以在任意组件中以 this.$ router 的形式访问路由实例,以 this.$ route 的形式访问当前路由。
About.vue:
export default {
computed: {
username() {
// 获取当前路由参数params
return this.$route.params.username
},
},
methods: {
goToIndex() {
// 跳转到首页
this.$router.push('/');
},
},
}
很多时候,我们需要将给定匹配模式的路由映射到同一个组件。例如,我们可能有一个 User 组件,它应该对所有用户进行渲染,但用户 ID 不同。在 Vue Router 中,我们可以在 路径 中使用一个 动态字段 来实现,我们称之为 路径参数 :
import User from '@/pages/User'
export default new Router({
// 4.定义路由:每个路由都需要映射到一个组件
routes: [
{
path: '/',
name: 'Home',
component: Home
}, {
// 动态字段以冒号开始
path: '/user/:id',
name: User,
component: User
}
]
})
现在像 /users/123 和 /users/456 这样的 URL 都可以访问到 User 组件。
路径参数 用冒号 : 表示。当一个路由被匹配时,它的 params 的值将在每个组件中以 this.$route.params 的形式暴露出来。因此,我们可以通过更新 User 的模板来呈现当前的用户 ID。
User.vue:
<template>
<div>
<span>用户ID:{{$route.params.id}}</span>
</div>
</template>
也可以在同一个路由中设置 多个路径参数,它们都会映射到 this.$route.params 上的相应字段。例如:
匹配模式 | 匹配路径 | $route.params |
---|---|---|
/users/:username | /users/hl | { username: ‘hl’ } |
/users/:username/posts/:postId | /users/hl/posts/123 | { username: ‘hl’, postId: ‘123’ } |
一些应用程序的 UI 由多层嵌套的组件组成。在这种情况下,URL 的片段通常对应于特定的嵌套组件结构,通过 Vue Router,可以使用嵌套路由配置来表达这种关系。
router/index.js:使用 children 来配置嵌套路由
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import HelloSon1 from '@/components/hello/HelloSon1'
import HelloSon2 from '@/components/hello/HelloSon2'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld,
// 配置嵌套路由:
children: [{
// 当 /#/hello1 匹配成功
// Hello1 将被渲染到 HelloWorld1 的 内部
path: 'hello1',
name: 'HelloSon1',
component: HelloSon1
}, {
// 当 /#/hello2 匹配成功
// Hello2 将被渲染到 HelloWorld2 的 内部
path: 'hello2',
name: 'HelloSon2',
component: HelloSon2
}]
}
]
})
App.vue 还是保持不变:
<div id="app">
<img src="./assets/logo.png">
<router-view/>
</div>
上面的 < router-view />是一个顶层的 router-view。它渲染 顶层 路由匹配的组件。同样地,组件中也可以包含自己嵌套的 < router-view />。例如我们在 HelloWorld 组件的模板内添加一个 < router-view />:
<div class="hello">
<span>{{msg}}</span>
<p>
<router-link to="/hello1">hello1</router-link>
<router-link to="/hello2">hello2</router-link>
</p>
<-- 对应在在路由中配置的 children -->
<router-view />
</div>
如上所示,children 配置只是另一个路由数组,就像 routes 本身一样。因此,可以根据需要,不断地嵌套视图。
除了使用 < router-link > 创建 a 标签来定义导航链接,我们还可以借助 router 的实例方法,通过编写代码来实现。
this.$router.push(...);
当你点击 < router-link > 时,内部会调用这个方法,所以点击 < router-link :to=“…'”> 相当于调用 this.$router.push(…) 。
声明式 | 编程式 |
---|---|
< router-link :to=“…” > | router.push(…) |
该方法的参数可以是一个字符串路径,或者一个描述地址的对象。例如:
// 字符串路径
router.push('/helloworld')
// 带有路径的对象
router.push({ path: '/user/123' })
// 命名的路由,并加上参数,让路由建立 url
router.push({ name: 'user', params: { id: 123 } })
// 带查询参数,结果是 /register?plan=private
router.push({ path: '/register', query: { plan: 'private' } })
// 带 hash,结果是 /about#team
router.push({ path: '/about', hash: '#team' })
注意:name 配合 params 一起使用, path 和 query 一起使用; params 和 path 不能一起使用。
this.$router.replace(...);
它的作用类似于 this.$router.push,唯一不同的是,它在导航时不会向 history 添加新记录,正如它的名字所暗示的那样——它取代了当前的条目。
也可以直接在传递给 router.push 的 routeLocation 中增加一个属性 replace: true :
this.$router.push({path: '/helloworld', replace: true})
// 相当于
this.$router.replace({path: '/helloworld'})
该方法采用一个整数作为参数,表示在历史堆栈中前进或后退多少步,类似于 window.history.go(n) 。
// 向前移动一条记录,与 router.forward() 相同
this.$router.go(1)
// 返回一条记录,与 router.back() 相同
this.$router.go(-1)
// 前进 3 条记录
this.$router.go(3)
// 如果没有那么多记录,静默失败
this.$router.go(-100)
this.$router.go(100)
router.push、router.replace 和 router.go 是 window.history.pushState、window.history.replaceState 和 window.history.go 的翻版,它们确实模仿了 window.history 的 API。
值得一提的是,无论在创建路由器实例时传递什么样的 history 配置,Vue Router 的导航方法( push、replace、go )都能始终正常工作。
除了 path 之外,还可以为任何路由提供 name,有以下优点:
要链接到一个命名的路由,可以向 router-link 组件的 to 属性传递一个对象:
<router-link :to="{ name: 'User', params: { username: 'hl' }}">
User
</router-link>
这跟代码调用 router.push() 是一回事:
this.$router.push({ name: 'User', params: { username: 'hl' } })
在这两种情况下,路由将导航到路径 /user/hl。
有时候想同时展示多个视图,而不是嵌套展示。
例如:创建一个布局,有 sidebar (侧导航) 和 main (主内容) 两个视图,这个时候命名视图就派上用场了。你可以在界面中拥有多个单独命名的视图,而不是只有一个单独的出口。
如果 router-view 没有设置名字,那么默认为 default。
<router-view class="view left-sidebar" name="LeftSidebar"></router-view>
<router-view class="view content"></router-view>
<router-view class="view right-sidebar" name="RightSidebar"></router-view>
一个视图使用一个组件渲染,因此对于同个路由,多个视图就需要多个组件,使用 components 配置( 带上 s ):
export default new Router({
routes: [
{
path: '/',
// 多个视图
components: {
default: Content,
// LeftSidebar: LeftSidebar 的缩写
// 与 `` 上的 `name` 属性匹配
LeftSidebar,
RightSidebar,
}
}
]
})
我们也有可能使用命名视图创建 嵌套视图 的复杂布局。
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
}
}]
}
重定向也是通过 routes 配置来完成,下面例子是从 / 重定向到 /user:
export default new Router({
routes: [
{
path: '/',
redirect: '/user'
}
]
})
重定向的目标也可以是一个命名的路由:
export default new Router({
routes: [
{
path: '/',
redirect: { name: 'User' }
}
]
})
甚至是一个方法,动态返回重定向目标:
export default new Router({
routes: [
{
path: '/',
redirect: to => {
// 方法接收目标路由作为参数
// return 重定向的字符串路径/路径对象
return 'user';
return { path: '/user', query: { username: 'hl' } }
},
}
]
})
注意:在写 redirect 的时候,可以省略 component 配置,因为它从来没有被直接访问过,所以没有组件要渲染。唯一的例外是 嵌套路由 :如果一个路由记录有 children 和 redirect 属性,它也应该有 component 属性。
重定向 是指当用户访问 / 时,URL 会被 /user 替换,然后匹配成 /user。那么什么是别名呢?
将 / 别名为 /user,意味着当用户访问 /user 时,URL 仍然是 /,但会被匹配为用户正在访问 /user。
export default new Router({
routes: [
{
path: '/',
component: Helloworld,
// 别名
alias: '/user'
}
]
})
路径为 /user,但是访问的是 / ,对应 HelloWorld.vue :
通过 别名 ,可以自由地将 UI 结构映射到一个任意的 URL,且不受配置的嵌套结构的限制。使别名以 / 开头,以使嵌套路径中的路径成为绝对路径。甚至可以将两者结合起来,用一个数组提供多个别名:
const routes = [
{
path: '/user',
component: User,
children: [
// 为这 3 个 URL 呈现 User
// - /user
// - /view
// - /user/index
{ path: '', component: Content, alias: ['/view', 'index'] },
],
},
]
如果路由有参数,请确保在任何绝对别名中包含它们:
const routes = [
{
path: '/user/:id',
component: User,
children: [
// 为这 3 个 URL 呈现 UserDetails
// - /user/24
// - /user/24/profile
// - /24
{ path: 'profile', component: UserDetails, alias: ['/:id', ''] },
],
},
]
在组件中可以使用 $route 获取传递的参数,但它只能用于特定的 URL,所以限制了组件的灵活性,另一种方式我们可以通过 props 配置来解除这种行为:
使用 $route 获取传递的参数:
const User = {
template: 'User {{ $route.params.id }}'
}
const routes = [{ path: '/user/:id', component: User }]
通过 props 获取参数:
const User = {
// 请确保添加一个与路由参数完全相同的 prop 名
props: ['id'],
template: 'User {{ id }}'
}
// 设置 props
const routes = [{ path: '/user/:id', component: User, props: true }]
上面例子即为 布尔模式 。
当 props 设置为 true 时,$route.params 将被设置为组件的 props。
当 props 是一个 对象 时,它将原样设置为组件 props。
当 props 是静态的时候很有用,例如弹窗的显隐:
const User = {
props: ['userPopup1', 'userPopup2'],
template: '<div>
<p v-if='userPopup1'>弹窗1</p>
<p v-if='userPopup2'>弹窗2</p>
</div>'
}
const routes = [
{
path: '/user',
component: User,
props: { userPopup1: false, userPopUp2: true }
}
]
创建一个返回 props 的函数,可以将参数转换为其他类型,将静态值与基于路由的值相结合等等。
const Search = {
template: '{{ id }}'
props: ['id']
}
const routes = [
{
path: '/search',
component: Search,
props: route => ({ id: route.query.id })
}
]
URL /search?id=123 将传递 {id: 123} 作为 props 传给 Search 组件。
vue-router 分为 hash 和 history 模式。
前者为其默认模式,url 的表现形式为:http://yoursite.com#home,比较难看。
后者的 url 表现形式为:http://yoursite.com/home,比较美观。
但如果要使用history模式,我们需要在后端进行额外配置
export default new Router({
// history模式的配置方法
mode: 'history',
routes: [
{
path: '/',
name: 'Home',
component: Home
}
]
})
服务器配置请参考官方链接:服务器配置示例