注意: 本文所有示例代码详见:vue-rouer-demo
1.What | 什么是Vue Router
Vue Router
是Vue.js提供的官方路由管理器,它和Vue.js深度集成,使构建单页面应用非常方便。
2.Why | 为什么要使用Vue Router
大家打开LorneNote个网站,这是我的一个blog网站,采用传统的开发模式,鼠标右击,在出现的菜单里选择View Page Source 查看资源文件,大家会看到它对应的是一个HTML文件,然后你回到网站里点击归档栏,再次右击查看源文件,你会看到整个页面被重新加载,对应归档的HTML文件,即:
- https://lornenote.com -----> LorneNote HTML文件
- https://lornenote.com/archives/ -----> 归档 | LorneNote HTML文件
也就是说每一个URL对应一个HTML文件,这样每次切换页面的时候我们都需要重新加载我们的页面,非常影响用户体验。
然后就诞生了单页面形式SPA(single page applications)。在单页面模式下,不管我们访问什么页面,都返回index.html
,类似这样:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="/favicon.ico">
<title>hello-world</title>
<link href="/app.js" rel="preload" as="script"></head>
<body>
<noscript>
<strong>We're sorry but hello-world doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
<script type="text/javascript" src="/app.js"></script></body>
</html>
在单文件模式里,我们依然可以跳到不同的HTML文件,但我们一般不会这样做,一个index.html就满足了我们的需求,用户切换URL的时候,不再是重新加载我们的页面,而是根据URL的变化,执行相应的逻辑,数据会通过接口的形式返回给我们,而后做页面更新。Vue Router就是为了解决这样的事情,它可以做这些事情:
- 提供URL和组件之间的映射关系,并在URL变化的时候执行对象逻辑
- 提供多种方式改变URL的API(URL的变化不会导致浏览器刷新)
3.How | Vue Router 如何使用
核心使用步骤
- 安装并导入VueRouter,调用Vue.use(VueRouter),这样的话可以使用
<router-view>
和<router-link>
等全局组件
// 安装命令
$ npm install vue-router
// main.js
import App from './App.vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
- 定义路由组件入口
// App.vue
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<router-view></router-view>
</div>
</template>
- 使用定义好的路由组件配置路由列表
// routes.js
import HelloWorld from './components/HelloWorld'
const routes = [
{path: '/', component: HelloWorld, name:'home'}
]
export default routes
- 创建路由实例,并通过路由列表初始化路由实例
// main.js
import routes from'./routes'
const router = new VueRouter({
routes
})
- 将创建好的路由实例挂载到跟实例,这样我们就可以使用this.$route全局钩子来操作路由管理器为我们提供的一些属性。
// main.js
new Vue({
router,
render: h => h(App),
}).$mount('#app')
注意:
this.$router
代表我们刚刚实例化的全局路由实例,它和我们导入router相同,只是为了使用方便,不用在组件中导入了。
this.$route
,写法上少了一个r,代表任何组件的当前路由。
路由动态匹配
有时候我们需要映射不同的路由给相同的组件
// routes.js
{ path:'/user/:id', component:User}
// HelloWorld.vue
<router-link to="/user/123">张三-single params</router-link><br>
在User组件中,可以以this.$route.params
的形式接收参数id
<template>
<div>User
{
{ this.$route.params.id }} // 123
</div>
</template>
动态匹配是以冒号区隔的,我们可以有多个动态段:
// routes.js
{ path:'/user/:userName/userId/:id', component:User},
// HelloWorld.vue
<router-link to="/user/王五/userId/789">王五-mutiple params</router-link>
// User.vue
<template>
<div>User
{
{ this.$route.params }} // { "userName": "王五", "id": "789" }
</div>
</template>
路由routes与path、$route.params三者的关系见下表:
路由模式 | 匹配path | $route.params |
---|---|---|
/user/:userName/userId/:id | /user/王五/userId/789 | { “userName”: “王五”, “id”: “789” } |
除了$route.parmas
,$route
还封装了其他的信息如:
$route.query
:用于获取URL中的查询,
$route.hash
:用于获取url中#之后的信息(自己写的路径带#,值会包含#,如果是history模式下自动追加的#,则值不包含这个#),如果没有,值为空,如果URL中有多个#,从最后一个开始。
我们重写一下上文的例子:
// HelloWorld.vue
<router-link to="/user/Query/userId/101?code=123">Query</router-link><br>
<router-link to="/user/Hash/userId/102#hash=123">Hash</router-link><br>
// User.vue
<template>
<div>User
{
{ this.$route.query }} // { "code": "123" }
{
{ this.$route.hash }} // #hash=123 原路径:http://localhost:8081/#/user/Hash/userId/102#hash=123
</div>
</template>
由于vue-router使用 path-to-regexp作为路径path的匹配引用,所以我们可以使用正则表达式作为路径:
// routes.js
{ path:'/icon