[TOC]
## 1. 什么是路由
1. 对于普**通的网站**,所有的超链接都是URL地址,所有的URL地址都对应服务器上对应的资源;
2. 对于**单页面应用程序**来说,主要通过URL中的hash(#号)来实现不同页面之间的切换,同时,hash有一个特点:HTTP请求中不会包含hash相关的内容;**所以,单页面程序中的页面跳转主要用hash实现;**
3. **在单页面应用程序中,这种通过hash改变来切换页面的方式,称作前端路由(区别于后端路由);**
## 2. 在 vue 中使用 vue-router
![](https://img.kancloud.cn/54/d9/54d9f51ad937286210f434cc84755a5c_397x207.png)
url 变化:
![](https://img.kancloud.cn/2c/9d/2c9d1854bca7d63f067ee1a2e8affdff_783x61.png)
![](https://img.kancloud.cn/95/2d/952d2b28758c58aecc6e33e05f384686_809x76.png)
1. 导入 vue-router 组件类库:
~~~
<script src="./lib/vue-router-2.7.0.js"></script>
~~~
2. 使用 router-link 组件来导航
~~~
<!-- 2. 使用 router-link 组件来导航 -->
<router-link to="/login">登录</router-link>
<router-link to="/register">注册</router-link>
~~~
3. 使用 router-view 组件来显示匹配到的组件
**路由控制这里的显示**
~~~
<!-- 3. 使用 router-view 组件来显示匹配到的组件 -->
<router-view></router-view>
~~~
4. 创建使用`Vue.extend`创建组件
~~~
// 4.1 使用 Vue.extend 来创建登录组件
var login = Vue.extend({
template: '<h1>登录组件</h1>'
});
// 4.2 使用 Vue.extend 来创建注册组件
var register = Vue.extend({
template: '<h1>注册组件</h1>'
});
~~~
5. 创建一个路由 router 实例,通过 routers 属性来定义路由匹配规则
~~~
// 5. 创建一个路由 router 实例,通过 routers 属性来定义路由匹配规则
var router = new VueRouter({
routes: [
{ path: '/login', component: login },
{ path: '/register', component: register }
]
});
~~~
6. 使用 router 属性来使用路由规则
~~~
// 6. 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
router: router // 使用 router 属性来使用路由规则
});
~~~
整体
```
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="./lib/vue-2.4.0.js"></script>
<!-- 1. 安装 vue-router 路由模块 -->
<script src="./lib/vue-router-3.0.1.js"></script>
<style>
.router-link-active,
.myactive {
color: red;
font-weight: 800;
font-style: italic;
font-size: 80px;
text-decoration: underline;
background-color: green;
}
.v-enter,
.v-leave-to {
opacity: 0;
transform: translateX(140px);
}
.v-enter-active,
.v-leave-active {
transition: all 0.5s ease;
}
</style>
</head>
<body>
<div id="app">
<!-- <a href="#/login">登录</a> -->
<!-- <a href="#/register">注册</a> -->
<!-- router-link 默认渲染为一个a 标签 -->
<router-link to="/login" tag="span">登录</router-link>
<router-link to="/register">注册</router-link>
<!-- 这是 vue-router 提供的元素,专门用来 当作占位符的,将来,路由规则,匹配到的组件,就会展示到这个 router-view 中去 -->
<!-- 所以: 我们可以把 router-view 认为是一个占位符 -->
<transition mode="out-in">
<router-view></router-view>
</transition>
</div>
<script>
// 组件的模板对象
var login = {
template: '<h1>登录组件</h1>'
}
var register = {
template: '<h1>注册组件</h1>'
}
/* Vue.component('login', {
template: '<h1>登录组件</h1>'
}) */
// 2. 创建一个路由对象, 当 导入 vue-router 包之后,在 window 全局对象中,就有了一个 路由的构造函数,叫做 VueRouter
// 在 new 路由对象的时候,可以为 构造函数,传递一个配置对象
var routerObj = new VueRouter({
// route // 这个配置对象中的 route 表示 【路由匹配规则】 的意思
routes: [ // 路由匹配规则
// 每个路由规则,都是一个对象,这个规则对象,身上,有两个必须的属性:
// 属性1 是 path, 表示监听 哪个路由链接地址;
// 属性2 是 component, 表示,如果 路由是前面匹配到的 path ,则展示 component 属性对应的那个组件
// 注意: component 的属性值,必须是一个 组件的模板对象, 不能是 组件的引用名称;
// { path: '/', component: login },
{ path: '/', redirect: '/login' }, // 这里的 redirect 和 Node 中的 redirect 完全是两码事
{ path: '/login', component: login },
{ path: '/register', component: register }
],
linkActiveClass: 'myactive'
})
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {},
methods: {},
router: routerObj // 将路由规则对象,注册到 vm 实例上,用来监听 URL 地址的变化,然后展示对应的组件
});
</script>
</body>
</html>
```
## router-view的name属性
通过名称,将组件渲染到对应的router-view上
1. 通过name属性,标识router-view,不写默认就是default
```
<router-view></router-view>
<router-view name="router1"></router-view>
```
2. components指定多个渲染,而不是component
```
routes: [ // 路由匹配规则
{ path: '/', redirect: '/login' }, // 这里的 redirect 和 Node 中的 redirect 完全是两码事
{ path: '/login', components: {default:login,router1:t1} },
{ path: '/register', components: {default:register,router2:t2} }
],
```
完整
```
<body>
<div id="app">
<router-link to="/login" tag="span">登录</router-link>
<router-link to="/register">注册</router-link>
<router-view></router-view>
<router-view name="router1"></router-view>
<router-view name="router2"></router-view>
</div>
<script>
// 组件的模板对象
var login = {
template: '<h1>登录组件</h1>'
}
var register = {
template: '<h1>注册组件</h1>'
}
var t1 = {
template: '<h1>router1我来了</h1>'
}
var t2 = {
template: '<h1>router2我来了</h1>'
}
var routerObj = new VueRouter({
routes: [ // 路由匹配规则
{ path: '/', redirect: '/login' }, // 这里的 redirect 和 Node 中的 redirect 完全是两码事
{ path: '/login', components: {default:login,router1:t1} },
{ path: '/register', components: {default:register,router2:t2} }
],
linkActiveClass: 'myactive'
})
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {},
methods: {},
router: routerObj // 将路由规则对象,注册到 vm 实例上,用来监听 URL 地址的变化,然后展示对应的组件
});
</script>
</body>
```
![](https://img.kancloud.cn/83/ae/83ae57650a03cb436e0097c57f2fe236_652x382.png)
点击注册
![](https://img.kancloud.cn/23/55/2355588b895f7dc7a552673996133a3c_655x301.png)
## 设置路由高亮
## 设置路由切换动效
**## 在路由规则中定义参数**
**1.指定实参**
~~~
<router-link to="/login/12/ls">登录</router-link>
~~~
**2. 通过 `this.$route.params`来获取路由中的参数**:
~~~
var login = {
template: '<h1>登录 --- {{ $route.params.id }} --- {{ $route.params.name }}</h1>',
data(){
return {
msg: '123'
}
},
created(){ // 组件的生命周期钩子函数
console.log(this.$route.params.id)
}
}
~~~
**3. 在规则中定义路径对应的参数**
在router对象中指定id和name
~~~
var router = new VueRouter({
routes: [
{ path: '/login/:id/:name', component: login },
{ path: '/register', component: register }
]
})
~~~
## **路由路径中传递参数**
~~~
如果在路由中,使用 查询字符串,给路由传递参数,则 不需要修改 路由规则的 path 属性
~~~
<router-link to="/login?id=10&name=zs">登录</router-link>
~~~
var login = {
template: '<h1>登录 --- {{ $route.query.id }} --- {{ $route.query.name }}</h1>',
data(){
return {
msg: '123'
}
},
~~~
完整代码
~~~
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="./lib/vue-2.4.0.js"></script>
<script src="./lib/vue-router-3.0.1.js"></script>
</head>
<body>
<div id="app">
<!-- 如果在路由中,使用 查询字符串,给路由传递参数,则 不需要修改 路由规则的 path 属性 -->
<router-link to="/login?id=10&name=zs">登录</router-link>
<router-link to="/register">注册</router-link>
<router-view></router-view>
</div>
<script>
var login = {
template: '<h1>登录 --- {{ $route.query.id }} --- {{ $route.query.name }}</h1>',
data(){
return {
msg: '123'
}
},
created(){ // 组件的生命周期钩子函数
// console.log(this.$route)
// console.log(this.$route.query.id)
}
}
var register = {
template: '<h1>注册</h1>'
}
var router = new VueRouter({
routes: [
{ path: '/login', component: login },
{ path: '/register', component: register }
]
})
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {},
methods: {},
// router: router
router
});
</script>
</body>
</html>
~~~
## **使用 `children` 属性实现路由嵌套**
![](https://img.kancloud.cn/60/84/6084ee181c1034241bf04f6c06666c17_1027x359.png)
~~~
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="./lib/vue-2.4.0.js"></script>
<script src="./lib/vue-router-3.0.1.js"></script>
</head>
<body>
<div id="app">
<router-link to="/account">Account</router-link>
<! -- 第一个router站位 -->
<router-view></router-view>
</div>
<template id="tmpl">
<div>
<h1>这是 Account 组件</h1>
<router-link to="/account/login">登录</router-link>
<router-link to="/account/register">注册</router-link>
<! -- 第二个router站位 子router -->
<router-view></router-view>
</div>
</template>
<script>
// 组件的模板对象
var account = {
template: '#tmpl'
}
var login = {
template: '<h3>登录</h3>'
}
var register = {
template: '<h3>注册</h3>'
}
var router = new VueRouter({
routes: [
{
path: '/account',
component: account,
// 使用 children 属性,实现子路由,同时,子路由的 path 前面,不要带 / ,否则永远以根路径开始请求,这样不方便我们用户去理解URL地址
children: [
{ path: 'login', component: login },
{ path: 'register', component: register }
]
}
// { path: '/account/login', component: login },
// { path: '/account/register', component: register }
]
})
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {},
methods: {},
router
});
</script>
</body>
</html>
~~~
## **路由前操作router.beforeEach**
> 在前端路由跳转中,路由跳转前都是会经过beforeEach,而beforeEach可以通过next来控制到底去哪个路由。利用这一特点,可以做发送请求时的操作:例如:权限校验(是否登录、页面是否存在)
beforeEach需要三个参数:
**to: Route**: 即将要进入的目标路由对象
**from: Route**: 当前导航正要离开的路由
**next: Function**: 一定要调用该方法来 **resolve** 这个钩子。执行效果依赖 next 方法的调用参数。
代码:
```
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requireAuth)){ // 判断该路由是否需要登录权限
if (token) { // 判断当前的token是否存在
next();
}
else {
next({
path: '/login',
// 将跳转的路由path作为参数,登录成功后跳转到该路由(to原来的路由对象)
query: {redirect: to.fullPath}
})
}
}
else {
next();
}
});
```
但是除了用户请求特定页面时(拦截是否登录),登录后继续请求这个页面。正常登录时不需要跳转。
```
if(this.$route.query.redirect){
let redirect = this.$route.query.redirect;
this.$router.push(redirect);
}else{
this.$router.push('/');
}
```
## **router.push**
`router.push(location) `: 用来进行页面跳转
* 除了使用 创建 a 标签来定义导航链接,我们还可以借助 router 的实例方法,通过编写代码来实现。
* 想要导航到不同的 URL,则使用 router.push 方法。这个方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,则回到之前的 URL。当你点击时,这个方法会在内部调用,所以说,点击 等同于调用 router.push(…)。
声明式: `<router-link :to="..."> `
编程式:router.push(...)
该方法的参数可以是一个字符串路径,或者一个描述地址的对象。
~~~
// 字符串
router.push('home')
// 对象
this.$router.push({path: '/login?url=' + this.$route.path});
// 命名的路由
router.push({ name: 'user', params: { userId: 123 }})
// 带查询参数,变成/backend/order?selected=2
this.$router.push({path: '/backend/order', query: {selected: "2"}});
// 设置查询参数
this.$http.post('v1/user/select-stage', {stage: stage})
.then(({data: {code, content}}) => {
if (code === 0) {
// 对象
this.$router.push({path: '/home'});
}else if(code === 10){
// 带查询参数,变成/login?stage=stage
this.$router.push({path: '/login', query:{stage: stage}});
}
});
// 设计查询参数对象
let queryData = {};
if (this.$route.query.stage) {
queryData.stage = this.$route.query.stage;
}
if (this.$route.query.url) {
queryData.url = this.$route.query.url;
}
this.$router.push({path: '/my/profile', query: queryData});
~~~
### replace
> 类型: boolean
> 默认值: false
设置 replace 属性的话,当点击时,会调用 router.replace() 而不是 router.push(),于是导航后不会留下 history 记录。即使点击返回按钮也不会回到这个页面。
//加上replace: true后,它不会向 history 添加新记录,而是跟它的方法名一样 —— 替换掉当前的 history 记录。
~~~
this.$router.push({path: '/home', replace: true})
//如果是声明式就是像下面这样写:
<router-link :to="..." replace></router-link>
// 编程式:
router.replace(...)
~~~
# 缓存
tab切换,缓存已渲染的数据,不会触发生命mounted
页面现在默认有缓存机制,如果不想缓存,添加meta: { notCache: true },并且name属性要和vue页面 export default 里的name属性对应
- vue
- 为什么要学vue
- 数据双向绑定
- vue指令
- v-bind创建HTML节点属性
- v-on绑定事件
- v-cloak
- v-text
- v-for和key属性
- v-if和v-show
- 案例1
- 自定义指令
- vue样式
- vue生命周期
- vue过滤器
- 自定义键盘修饰符
- 跨域请求
- vue组件
- 组件基础
- 引入vue文件组件
- 引入render函数作为组件
- 兄弟间组件通信
- 组件函数数据传递练习
- 路由
- 数据监听
- webpack
- vue校验
- vue笔记
- form表单中input前部分默认输入,切不可修改
- mixins
- 部署到nginx
- scope
- render
- 下载文件
- vue动态组件
- axios
- Promise
- vue进阶
- node-vue-webpack搭建
- vue事件
- 插槽
- vuex
- vuex基础
- vuex命名空间
- HTML递归?
- this.$nextTick异步更新dom
- elementui
- table
- 修改element ui样式
- form
- 优质博客
- vuex state数据与form元素绑定
- es6
- Promise