一、hash $ history
Vue路由支持两种模式hash、history两种模式,默认使用hash模式
1.hash模式
以#/
开始匹配,这种叫作哈希模式(hash)。这里的 # 和 css 里的 # 是一个意思。hash 也称作锚点,本身是用来做页面定位的,她可以使对应 id 的元素显示在可视区域内。
由于 hash 值变化不会导致浏览器向服务器发出请求,而且 hash 改变会触发hashchange
事件,浏览器的进后退也能对其进行控制,所以人们在 html5 的 history 出现前,基本都是使用 hash 来实现前端路由的。
2.history模式
history模式以/
开始匹配,就是我们常见的方式没有 # 符号
已经有 hash 模式了,而且 hash 能兼容到IE8, history 只能兼容到 IE10,为什么还要搞个 history 呢?
首先,hash 本来是拿来做页面定位的,如果拿来做路由的话,原来的锚点功能就不能用了。其次,hash 的传参是基于 url 的,如果要传递复杂的数据,会有体积的限制,而 history 模式不仅可以在url里放参数,还可以将数据存放在一个特定的对象中。
最重要的一点是history模式下改变url的方式会导致浏览器向服务器发送请求,这不是我们想看到的,我们需要在服务器端做处理:如果匹配不到任何静态资源,则应该始终返回同一个 html 页面
二、简单使用
1.引入vue-router.js文件
(1).如果在一般的html中使用Vue路由,可以通过script标签引入vue-router.js文件即可
(2).如果在一个模块化工程中使用它,必须要通过 Vue.use()
明确地安装路由功能:
在你的文件夹下的 src 文件夹下的 main.js 文件内写入以下代码
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
2.定义路由
定义路由时,可以通过一个数组来存放多个对象,每个对象是一个路由配置,通过path
属性来指定访问路径,通过component
属性来指定路径匹配哪个组件
var tempOne = { template: '<p>this is one page</p>' };
var tempTwo = { template: '<p>this is two page</p>' };
var routes = [
{ path: '/one', component: tempOne },
{ path: '/two', component: tempTwo }
];
3.创建VueRouter实例并加载路由
使用VueRouter
构建函数来创建路由实例,并通过routes
属性来加载定义了路由的对象
var router = new VueRouter({
routes
});
4.在Vue实例中加载路由
在vue实例中通过router
配置参数注入路由
var vm = new Vue({
router
});
通过注入路由器,我们可以在任何组件内通过this.$router
访问路由器,也可以通过 this.$route
访问当前路由
5.定义导航标签
使用router-link
标签并通过to
属性来指向具体链接
<router-link to="/one">第一个页面</router-link>
<router-link to="/one">第二个页面</router-link>
router-link
标签会被渲染为对应的a标签,例如:
<a href="#/one">第一个页面</a>
另外,当 <router-link>
对应的路由匹配成功,将自动设置 class 属性值 .router-link-active
6.定义路由视图
每次切换路由,路由内容都会展示在<router-view>
标签中
完整例子
<head>
<title>vue</title>
<meta charset="utf-8">
<script src="./vue.js"></script>
<script src="vue-router.js"></script>
</head>
<body>
<div id="root">
<div>
<router-link to="/one">第一个</router-link>
<router-link to="/two">第二个</router-link>
</div>
<router-view/>
</div>
<script>
var tempOne = {
template: "<div>this is one page</div>"
};
var tempTwo = {
template: "<div>this is one two</div>"
};
var routes = [
{path: '/one', component: tempOne},
{path: '/two', component: tempTwo}
];
var router = new VueRouter({
routes
});
var vm = new Vue({
el: '#root',
router
});
</script>
</body>
二、动态路由
1.动态路由匹配
(1).有时候我们需要通过不同的路径来匹配同一个路由从而调用同一个组件来进行渲染,例如要求/user/one
和/user/two
都能匹配到同一个路由来使用user
组件进行渲染,此时可以通过动态路径参数
达到这个效果,动态路径参数
通过:
来标记
(2).当匹配到一个路由时,参数值会被设置到this.$route.params
,可以在每个组件内使用
(3).可以在一个路由中设置多段”路径参数”,对应的值都会设置到$route.params
中,例如:/user/:username/post/:post_id
<body>
<div id="root">
<router-link to="/user/one">用户一</router-link>
<router-link to="/user/two">用户二</router-link>
<router-view/>
</div>
<script>
const user = {
template: "<div>user {{$route.params.id}}</div>"
};
const routes = [{
path: '/user/:id',
component: user
}];
const router = new VueRouter({
routes
});
var vm = new Vue({
el: '#root',
router
})
</script>
</body>
2.响应路由参数的变化
在vue中,当重复调用同一组件进行渲染时,会复用组件实例来提高性能,例如从路由/user/one
到/user/two
,此时第一次建的组件实例会被复用,这同时意味着组件的生命周期钩子不会再被调用。
因此,当复用组件时,如果需要对路由参数的变化作出响应的话,可以在组件对象中通过watch
属性对$route
对象进行检测,或者调用beforeRouteUpdate
方法对其进行检测。
需要注意的是,调用beforeRouteUpdate
方法时候,会传入三个参数,第三个参数是一个函数,只有调用了才可以继续路由
const user = {
template: "<div>user {{$route.params.id}}</div>",
watch: {
'$route' (to, from) {
console.log(to);
}
}
};
const user = {
template: "<div>user {{$route.params.id}}</div>",
beforeRouteUpdate (to, from, next) {
console.log(to);
next();
}
};
三、匹配优先级
有时候,同一个路径可以匹配多个路由,此时,匹配的优先级就按照路由的定义顺序:谁先定义的,谁的优先级就最高。
四、嵌套路由
先来看一下正常情况下使用路由的例子
<!DOCTYPE html>
<html>
<head>
<title>vue</title>
<meta charset="utf-8">
<script src="./vue.js"></script>
<script src="vue-router.js"></script>
</head>
<body>
<div id="root">
<div id="app">
<router-link to="/user/133">
<button>转换</button>
</router-link>
<router-view></router-view>
</div>
</div>
<script>
const User = {
template: '<div>User {{ $route.params.id }}</div>'
}
const router = new VueRouter({
routes: [{
path: '/user/:id',
component: User
}]
})
const vm = new Vue({
el: '#root',
router
})
</script>
</body>
</html>
此时点击”转换”按钮,可以在<router-view></router-view>
中显示出User
组件。现在出现一个需求:在User
组件中出现一个<router-view></router-view>
标签来进行路由显示,例如:
const User = {
template: `
<div class="user">
<h2>User {{$route.params.id}}</h2>
<router-view></router-view>
</div>
`
}
const UserProfile = {
template: '<div>UserProfile {{ $route.params.id }}</div>'
}
const UserPosts = {
template: '<div>UserPosts {{ $route.params.id }}</div>'
}
此时就出现了路由嵌套,要在嵌套的出口中渲染组件,需要在VueRouter
的参数中使用children
配置:
const router = new VueRouter({
routes: [{
path: '/user/:id',
component: User,
children: [{
path: 'profile',
component: UserProfile
}, {
path: 'posts',
component: UserPosts
}]
}]
})
当/user/:id/profile
匹配成功UserProfile
组件会被渲染在User
组件的<router-view>
中,
当/user/:id/posts
匹配成功UserPosts
组件会被渲染在User
组件的<router-view>
中。
需要注意的是,以/
开头的嵌套路径会被当作根路径,所以子路中不需要添加/
此时,基于上面的配置,当你访问/user/foo时,User
组件中的出口是不会渲染任何东西,这是因为没有匹配到合适的子路由。如果你想要渲染点什么,可以提供一个空的子路由:
const router = new VueRouter({
routes: [
{
path: '/user/:id', component: User,
children: [
{ path: '', component: UserHome },
]
}
]
})