本文是我在学习过程中记录学习的点点滴滴,目的是为了学完之后巩固一下顺便也和大家分享一下,日后忘记了也可以方便快速的复习。
Vue Router 实现路由控制实战
前言
今天学习的主要知识点是关于什么是单页面应用,Vue Router 实现前端路由控制的方法,路由之间传递参数的方法,路由跳转的常见方法,路由嵌套、命名路由、命名视图的应用,组件与路由间的解耦方法的理解和应用
一、什么是单页面应用及实现前端路由的基本原理
1.1、什么是单页面应用
概述:
根据不同的 url 地址,显示不同的内容,但是显示在同一个页面中,也就是只有一个页面,所以称为单页面应用,英文 SPA(SinglePage Application)。像移动端很多 App 都是单页面应用。
改变 url 地址,显示不同的页面,实现的手段就是前端路由。
1.2、什么是路由及前端路由
概念:
简单举例说明,假如我们有一台提供 Web 服务的服务器的网络地址是:122.22.33.11,而该 Web 服务又提供了三个可供用户访问的页面,其页面 URI 分别是:
http:// 122.22.33.11/
http:// 122.22.33.11/about
http:// 122.22.33.11/news
那么其路径就分别是 /,/about,/news。
当用户使用 http:// 122.22.33.11/about 来访问该页面时, Web 服务会接收到这个请求,然后会解析 URL 中的路径 /about, 在 Web 服务的程序中,该路径对应着相应的处理逻辑,程序会把请求交给路径所对应的处理逻辑,这样就完成了一次【路由分发】,这个分发就是通过【路由】来完成的。
简单的说,路由是根据不同的 url 地址展示不同的内容或页面。以前路由都是后台做的,通过用户请求的 url 导航到具体的 html页面,前端路由就是通过配置 js 文件,改变 url 地址,显示不同的页面,把这个工作拿到前端来做。即 URL 变化引起 UI 更新,而且页面不能刷新。
1.3、实现前端路由基本原理
要实现前端路由,需要解决两个核心问题:
如何改变 URL 却不引起页面刷新?
如何检测 URL 变化了?
目前的前端路由的实现方式主要有下面两种
(1)hash 路由:location.hash+hashchange 事件
(2)history 路由:history.pushState()+popState 事件
其实不管是哪种模式都是基于浏览器自身的特性。
(1)location.hash+hashchange 事件:实现基本原理
这种方法的好处在于支持 IE 浏览器。对早期的一些浏览器的支持比较好。hash 是什么:其实在之前的前端开发中,是有所接触的。
例如,在某些情况下,我们需要定位页面上的某些位置,就像下面的例子中展现的那样,我想要通过点击不同的链接按钮就跳转到指定的位置,这里我们使用的锚点定位其实就是 hash。
<div id=“content”>
<div class=“btn-container”>
<a class=“btn” href=“#image1”>图片 1
<a class=“btn” href=“#image2”>图片 2
</div>
<img src=“./xxx/xxx.jpg” id=“image1”>
<img src=“./xxx/xxx.jpg” id=“image2”>
</div>
location.hash 始终指向页面 url 中#之后的内容,比如:当当
前页面的 url =‘www.taobao.com’,可以在浏览器的控制台输入location.hash 为 空 ( 因 为 没 有 # ), 当 页 面 指 向 url =‘www.taobao.com/#/about’的时候,location.hash = ‘#/about’。通过读取 location.hash 可以知道当前页面所处的位置。通过hashchange 事件可以监听 location.hash 的变化,从而进行相应的处理即可。
那么如何触发 hash 的改变呢?这里主要由两种方法:
第一、设置 a 标签,href = ‘#/about’,当点击标签的时候,可以在当前 url 的后面增加上’#/about’,同时触发 hashchange,在回调函数中进行处理。
第二、直接在 js 中设置 location.hash = '#/about’即可,此时
url 会改变,也会触发 hashchange 事件。
说明:改变 URL 中的 hash 部分(#后面内容)不会引起页面刷新 。
(2)history.pushState()+popState 事件:实现基本原理
history 路 由 : 在 之 前 的 html 版 本 中 , 我 们 可 以 通 过history.back(), history.forward()和 history.go() 方法来完成在用户历史记录中向后和向前的跳转。而该实现方式是通过 pushState()修改 url 的地址,popstate 事件监听地址的改变。pushState()方法和 replaceState 事件是 html5 新增的,它们的配合使用不会引起页 面 刷 新 。
具 体 实 现 原 理 参 考 :https://www.renfei.org/blog/html5-introduction-3-history-api. html
在 Vue 中,Vue Router 是官方提供的路由管理器。它和
Vue.js 深度集成,因此,不管是采用 hash 的方式还是使用 history实现我们的前端路由都有很好的支持,所以下面我们采用 VueRouter 这一组件来实现我们的前端路由。
二、使用 Vue Router 实现前端路由控制
2.1、1. 下载安装 vue-router
在要安装的位置打开cmd窗口:
npm/cnpm install vue-router –S
然后把对应的 vue-router.js 或 vue-router.min.js 文件复制到项目下(安装的就是在项目下的话可以不用复制)。
<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">
<title>Document</title>
<script src="js/vue.js"></script>
<script src="js/vue-router.js"></script>
</head>
<body>
<div id="app">
<div>
<!--1.使用 router-link 组件来定义导航 -->
<!-- router-link 相应于 a 标签,to 相当于 href ,指要单击跳转到显示
那个组件的内容,默认最终浏览器还是会把 router-link 解析为 a 标签-->
<router-link to="/about">关于我们</router-link>
<router-link to="/news">新闻</router-link>
</div>
<div>
<!--2.router-view 指定显示路由导航内容的位置,也就是单击【关于
我们】或【新闻】连接的内容都在 router-view 组件指定位置显示 -->
<router-view></router-view>
</div>
</div>
<script>
//3.定义组件,也就是每个链接显示的内容
var About = {
template: '<h3>我是关于我们页面内容</h3>'
}
var News = {
template: '<h3>我是新闻页内容</h3>'
}
//4.配置路由。有多条路由,通常定义为一个常量数组,里面每个对象就是一个路由
const routes = [
// 定义路由格式:path 指定路由的 url,component 指定当单击 path
// 指定的 url 时显示哪个组件内容。所以 Home 组件不单独定义也行,即如下写法
// 也可以的,只不过阅读不方便
// {path:'/about',component:{template:'<h3>我是关于我们页面内
// 容</h3>'}}
{
path: '/about', component: About }, {
path: '/news', component: News }
]
//5.创建路由实例。能 new VueRouter 就是因为引入了 vue-router.js。
// 括号里要配置设置路由选项 routes,对象形式,告诉路由条目是什么
const router = new VueRouter({
// routes:routes//左边 routes 为要设置的路由选项 routes,右边
// routes 为选项值,也就是第 2 步中定义的 routes,名字当然可以不同,但是一
// 般设置为相同,这样可以简写为下面青绿色底纹写法(ES6 语法)。第 4 步不单
// 独定义,直接写在 routes:后面当然也可以的(见下面注释掉的内容)。
routes
/* routes: [
// 定义路由格式:path 指定路由的 url,component 指定
当单击 path 指定的 url 时显示哪个组件内容。所以 About 组件不单独定义也行, 即如下写法也可以的,只不过阅读不方便
{ path: '/about', component: { template: '<h3>我是关于
我们页面内容</h3>' } },
// { path: '/home', component: About }, { path: '/news', component: News }
] */
});
//6.创建 vue 根实例,并将上面的路由实例挂载到 vue 实例上,也称为注入路由,也就是告诉 vue 实例有这么一个路由了。
//怎么告诉呢?通过 router 选项
var vm = new Vue({
el: "#app", // router:router//同样:左右两边名称相同,可以简写(ES6 语法)
router//注入路由
})
</script>
</body>
刚进入时:
单击关于我们效果:
单击新闻效果:
三、Vue Router 实现前端路由控制完善理解
3.1、Vue Router创建路由实例默认采用 hash 路由
上面运行结果我们发现地址栏后面会自动在加一个#/,切换不同显示,即切换路由,后面显示就是#/about,#/news。为什么是这种显示模式呢?因为在创建路由实例时 vue Router 默认采用的是hash 路由配置模式(各种浏览器的兼容性比较好)。当在#/about,#/news 之间切换时,也就是当 URL 改变时,页面不会重新加载。
3.2、 通过 mode 选项可改为 history 路由
如何改为 history 路由呢?上面创建路由实例时只设置了一个必须的选项 routes,可以通过设置路由配置模式 mode 选项来改变默认路由模式,如果不想要 hash 路由模式,只需要设置 mode 为history 即可。
const router = new VueRouter({
routes,
mode:‘history’ //设置路由配置模式,注意,单引号不能少
});
这种 history 路由配置模式缺点,URL 的兼容性不是很好哦,有些浏览器下可能不能正常显示。
3.3、history 路由模式运行效果分析
从上面运行效果可以看出不论切换到【关于我们】还是【新闻】,地址栏不会有任何变化,可以说不从下面显示内容来看,都不知道切换到哪个导航了。不过观察生成的 html 代码发现在当前导航会增加一个 class 样式。
class=“router-link-exact-active router-link-active”
但是此样式没有效果显示出来,实际上内部只给出了样式名,没有设置具体样式,需要自己手动设置具体样式。
3.4、为当前【导航】添加样式
实际上不论是 hash 路由还是 history 路由模式,系统都会自动为当前导航添加样式的。比如添加如下样式:当前导航字体为红色大小为 20px 等
<style>
.router-link-active{
font-size:20px;
color:red;
text-decoration: none;
}
</style>
注意:样式名取后面一个名称即可,即上面的黄色代码
此时再运行效果如下图所示:
3.4.1、改进系统默认生成的样式名
系统默认样式名为.router-link-active,如果觉得太长或不好记忆可以改掉,如何改呢?
在创建路由实例时再加一个 linkActiveClass 选项,设置样式名。
const router = new VueRouter({
routes,
mode:‘history’,
linkActiveClass:‘active’});
此时样式就要改为如下:
<style>
.active{
font-size:20px;
color:red;
text-decoration: none;
}
</style>
3.5、配置根路由【路由重定向】
此外还有一个小问题:不论哪种路由配置模式,刚打开页面时既没有显示【关于我们】内容,也没有显示【新闻】内容,因为默认打开是进入根路由,而根路由是不存在的。因此,配置路由时再增加一个路由(找不到路由时就重新定向到 about)。
即在下面增加黄色底纹代码,表示找不到路由时,重新定向到 about。(定义路由格式:path 指定路由的 url,component 指定当单击 path 指定的 url 时显示哪个组件内容。)
const routes = [
{ path: ‘/about’, component: About },
{ path: ‘/news’, component: News },
{path:‘*’,redirect:‘/about’}//*表示找不到路由时,重定向到
about
]
四、前端路由嵌套
4.1、为导航【账户】添加【注册】和【登录】两个子导航【路由嵌套】
要实现上面功能,就要进行路由嵌套,就是进入【账户】之后又有【注册】、【登录】两个子路由。
<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">
<title>Document</title>
<script src="js/vue.js"></script>
<script src="js/vue-router.js"></script>
<style>
.container {
background-color: blanchedalmond;
margin-top: 10px;
width: 600px;
height: 300px;
}
.active {
font-size: 20px;
color: red;
text-decoration: none;
}
</style>
</head>
<body>
<div id="app">
<div>
<router-link to="/about">关于我们</router-link>
<router-link to="/news">新闻</router-link>
<router-link to="/account">账户</router-link>
</div>
<div class="container">
<router-view></router-view>
</div>
</div>
<!—- 注意书写位置在<script>外面 -->
<template id="tmpaccount">
<div>
<h3> 这里是账户页面 </h3>
// <!-- 生成嵌套子路由地址 -->
//<!-- /account/login 前面那个/不能少,否则,第二次以后单击登录/注册会有问题 -->
<router-link to="/account/login">登录</router-link>
<router-link to="/account/register">注册</router-link>
<div>
// <!-- 生成嵌套子路由渲染节点 -->
<router-view></router-view>
</div>
</div>
</template>
<script>
//1.定义组件,也就是每个链接显示的内容
var About = {
template: '<h3>我是关于我们页面内容</h3>'
}
var News = {
template: '<h3>我是新闻页内容</h3>'
}
var Account = {
template: '#tmpaccount' //这里模板内容变复杂了,所以单独定义
}
//增加 2 个组件
const Login = {
template: '<h4>这里是登录页面内容</h4>'
}
const Register = {
template: '<h4>这里是注册页面内容</h4>'
}
//2.配置路由。有多条路由,通常定义为一个常量数组,里面每个对象就是一个路由
const routes = [
{
path: '/about', component: About }, {
path: '/news', component: News }, {
path: '/account', component: Account, children: [{
//account 下的子路由
path: 'login', component: Login
}, {
path: 'register', component: Register
}
]
}, {
path: '*', redirect: '/about' }//*表示找不到路由时,重定向到 about
]
//3.创建路由实例。能 new VueRouter 就是因为引入了 vue-router.js。括号里要配置设置路由选项 routes,对象形式,告诉路由条目是什么
const router = new VueRouter({
routes, mode: 'history', linkActiveClass: 'active'
});
//4.创建 vue 根实例,并将上面的路由实例挂载到 vue 实例上,也称为注入路由
var vm = new Vue({
el: "#app", router//注入路由
})
</script>
</body>
运行效果如下:
也可以把 mode 改为 hash 路由模式,注释掉mode: ‘history’,即可,当然区别也就是在地址显示方式不一样。
4.1、< router-link >的 tag 属性应用
如上,<router-link>默认是转为<a>标签。实际上可以为
<router-link>增加 tag 属性指明转为其他标签,比如 button、li。
1、设置 tag=“button”
<router-link to=“/account/login” tag=“button”>登录</router-link>
<router-link to=“/account/register” tag=“button”>注册</router-link>
运行效果:
2、设置 tag=“li”
说明:改为 li,一般就要在外面套一层<ul>变成无序列表。
<ul>
<router-link to=“/account/login” tag=“li”>登录
</router-link>
<router-link to=“/account/register” tag=“li”>注册
</router-link>
</ul>
运行结果:
五、路由之间传参的两种方式及路由信息获取
在很多的情况下,例如表单提交,组件跳转之类的操作,我们需要使用到上一个表单、组件的一些数据,这时我们就需要将需要的参数通过参数传参的方式在路由间进行传递。
比如上面用户登录要传入用户名、密码,那么如何传递呢?
5.1、query 查询参数传参
总结:
使用query传参就是注意两点:
传参:
将我们需要的参数以 key=value 的方式放在 url 地址中:?name=’xzx’&pwd=’123
接参:
全部参数:{ {$route.query}},
用户名:{ {$route.query.name}},
密码:{ {$route.query.pwd}}
1、query 查询参数传参
就是将我们需要的参数以 key=value 的方式放在 url 地址中。类似如下:
login?name=’xzx’&pwd=’123’
当然这里的参数值:xzx,123 可以通过当前组件的表单中输入。之后,通过获取这两个参数值即可实现我们的需求。
单击【登录】时传递 name 和 pwd 参数,即将上面紫色底纹代码改为:
<router-link to=“/account/login?name=xzx&pwd=123” tag=“li”>登录</router-link>
2、进入 login 组件如何获取到传入的参数呢?
当我们将实例化的 VueRouter 对象挂载到 Vue 实例后,Vue
Router 在我们的 Vue 实例上创建了两个属性对象
$router(router 实例) 和 $route(当前页面的路由信息)。
通过 this.$route.query 可以获取到 query 查询参数(this 就表示当前 vm 实例,这里可以省略)。
上面例子中的如下代码:
var Login = {
template: ‘<h4>这里是登录页面内容</h4>’ }
改为如下:
var Login = {
template: ‘<h4>这里是登录页面内容,获取账户参数:{ {$route.query}},
用户名:{ {$route.query.name}},
密码:{ {$route.query.pwd}}</h4>’ }
运行结果:成功获取到了用户名和密码。
5.2、param 方式传参
总结
传参:
login/xzx/123456
因为这里没有指定参数名称。所以要在路由中定义:
path: ‘register/:name/:pwd’
接参(方式不变,和上面的一样):
全部参数:{ {$route.query}},
用户名:{ {$route.query.name}},
密码:{ {$route.query.pwd}}}
传递参数时采用类似 login/xzx/123456。
那么 xzx、123456分别代表什么,比如 xzx 是用户名还是密码或者其他字段,这个需要在路由中指明。比如单击【注册】时要传递用户名 xzx、密码 123456过去。即上面例子中青绿色底纹代码改为如下:
<router-link to=“/account/register/xzx/123456” tag=“li”>注册
</router-link>
不过,与 query 查询参数传参不同的是,在定义路由信息时,我们需要以占位符(:参数名)的方式将需要传递的参数指定到路由地址中。否则不知道上面传递的参数,如 xzx、123456 代表什么?即在路由中指明上面参数的含义:也就是增加下面青黄色底纹代码:
children: [{
path: ‘login’, component: Login
},{
path: ‘register/:name/:pwd’, component: Register
}]
进入 register 组件时如何获取传递过来的参数。与获取 query参数的方式相同,我们同样可以通过 vm.$route 获取到当前路由信息,通过 $route.params.参数名 的方式获取到通过 param 的方式进行参数传递的值,参数名也就是在路由中设置的参数名(/:后面的)。
定义注册 register 组件的代码改为如下,增加下面的黄色底纹代码:
const Register = {
template: ‘<h4>这里是注册页面内容,获取传递的参数:{ {$route.params}},
用户名:{ {$route.params.name}},
密码:{ {$route.params.pwd}}</h4>’ }
最终运行结果正确:成功获取到了用户名和密码。
5.2、$route.path 获取当前路由的路径
路由对象还有些其他属性,比如:$route.path,获取路由的当前路由的路径。
如在上面的例子中加入黄色底纹代码
const Register = {
template: ‘<h4>这里是注册页面内容,获取传递的参数:{ {$route.params}},
用户名:{ {$route.params.name}},
密码:{ {$route.params.pwd}},
路由路径{ {$route.path}}</h4>’ }
运行结果如下:获取到了当前路由,不过这里是 REST 风格的路由,也就说 xzx/123456 不是子路由,前面指明了为用户名和密码。(REST 即表述性状态传递,英文:Representational State Transfer,是一种 web 程序设计风格)
六、实现路由导航跳转的几种方式
6.1、this.$router.push跳转路由/添加路由
总结
这个方法就是通过按钮跳转页面并传递参数过去,通俗来讲就是通过this.$router.push方法来提交表单给导航栏替换路由实现导航跳转和传参。
在 push 方法中,参数可以是一个字符串路径,或者是一个描述地址的对象
// 字符串 => /account/register
this.$router.push(‘/account/register’)
// 对象 => /account/register
this.$router.push({path:‘/account/register’})
// 带查询参数 1
this.$router.push({path:‘/account/login’,query:{name:this.
name,pwd:this.pwd}})
// 带查询参数 2
this.$router.push({path:‘/account/login?name=’ + this.name+ ‘&pwd=’ + this.pwd})
上面传递参数我们都是“写死”的,现在我来改为由用户输入。
在 Vue Router 中具有三种导航方法,分别为 push、replace
和 go。我们前面例子中通过在页面上设置 router-link 标签进行路由地址间的跳转,就等同于执行 push 方法。
1.$router.push()跳转路由/添加路由
当我们需要跳转新页面时,我们就可以通过 push 方法将一条新的路由记录添加到浏览器的 history 栈中,通过 history 的自身特性,从而驱使浏览器进行页面的跳转。同时,因为在 history 会话历史中会一直保留着这个路由信息,所以当我们后退时还是可以退回到当前的页面。
在 push 方法中,参数可以是一个字符串路径,或者是一个描述地址的对象
// 字符串 => /account/register
this.$router.push(‘/account/register’)
// 对象 => /account/register
this.$router.push({path:‘/account/register’})
// 带查询参数 1
this.$router.push({path:‘/account/login’,query:{name:this.
name,pwd:this.pwd}})
// 带查询参数 2
this.$router.push({path:‘/account/login?name=’ + this.name+ ‘&pwd=’ + this.pwd})
需求:在上例中,单击【账户】进入账户页面,该页面有【登录】和【注册】两个导航链接,单击【登录】链接进入登录页面,该页面中提供用户名和密码输入框及【提交】按钮,单击【提交】按钮在当前页面显示出用户名和密码信息
<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">
<title>Document</title>
<script src="js/vue.js"></script>
<script src="js/vue-router.js"></script>
<style>
.container {
background-color: blanchedalmond;
margin-top: 10px;
width: 600px;
height: 300px;
}
.active {
font-size: 20px;
color: red;
text-decoration: none;
}
</style>
</head>
<body>
<div id="app">
<div>
<router-link to="/about">关于我们</router-link>
<router-link to="/news">新闻</router-link>
<router-link to="/account">账户</router-link>
</div>
<div class="container">
<router-view></router-view>
</div>
</div>
<template id="tmpaccount">
<div>
<h3> 这里是账户页面 </h3>
<!-- 生成嵌套子路由地址 -->
<!-- /account/login 前面那个/不能少,否则,第二次以后单
击登录/注册会有问题 -->
<ul>
<router-link to="/account/login" tag="li">登录
</router-link>
<router-link to="/account/register" tag="li">注册
</router-link>
</ul>
<div>
<!-- 生成嵌套子路由渲染节点 -->
<router-view></router-view>
</div>
</div>
</template>
<template id="tmplogin">
<form action="">
<div>
<h4>欢迎来到登录页面,请输入登录信息</h4> 用户名:
<input type="text" name="name" v-model="name" /><br>
密码:
<input type="password" name="pwd" v-model="pwd" /><br>
<input type="submit" value="提交" @click="submit">
</div>
<h4>你输入的登录信息是,用户名:
{
{this.$route.query.name}},
密码:{
{this.$route.query.pwd}}</h4>
</form>
</template>
<script>
//1.定义组件,也就是每个链接显示的内容
var About = {
template: '<h3>我是关于我们页面内容</h3>'
}
var News = {
template: '<h3>我是新闻页内容</h3>'
}
var Account = {
template: '#tmpaccount', //这里模板内容变复杂了,所以单独定义
}
//增加 2 个组件
const Login = {
template: '#tmplogin', data() {
return {
name: '',//为了获取用户输入数据,这里就要有对应存储数据属性
pwd: ''
}
}, methods: {
submit() {
this.$router.push({
//想跳到哪里就设置相应的路由,并传递参数信息。比如跳到注册页面/ account / register 也行
path: '/account/login', query: {
name: this.name, pwd:
this.pwd
}
})
}
},
}
const Register = {
template: '<h4>这里是注册页面内容</h4>'
}
//2.配置路由。有多条路由,通常定义为一个常量数组,里面每个对象就是一个路由
const routes = [
{
path: '/about', component: About }, {
path: '/news', component: News }, {
path: '/account', component: Account, children: [{
//account 下的子路由
path: 'login', component: Login
}, {
path: 'register', component: Register
}
]
}, {
path: '*', redirect: '/about' }//*表示找不到路由时,重定向到 about
]
//3.创建路由实例。能 new VueRouter 就是因为引入了vue - router.js。括号里要配置设置路由选项 routes, 对象形式,告诉路由条目是什么
const router = new VueRouter({
routes, // mode: 'history', //这里不能使用历史路由模式,否则跳转会有问题
linkActiveClass: 'active'
});
//4.创建 vue 根实例,并将上面的路由实例挂载到 vue 实例上,也称为注入路由
var vm = new Vue({
el: "#app", router//注入路由
})
</script>
</body>
运行效果:
如果要改为在【注册】页面显示信息,只要把 push 方法跳转对象更改下即可,如下:
this.$router.push({
//想跳到哪里就设置相应的路由,并传递参数信息。比
如跳到注册页面/account/register 也行
path:‘/account/register’,query:{name:this.name,p
wd:this.pwd}
})
6.2、$router.replace ()替换路由
replace 方法同样可以达到实现路由跳转的目的,不过,从名字中你也可以看出,与使用 push 方法跳转不同是,当我们使用replace 方法时,并不会往 history 栈中新增一条新的记录,而是会替换掉当前的记录,因此,无法通过后退按钮再回到被替换前的页面。
需求:在【账户】页面下有一个【替换路由】按钮,单击该按钮,跳转到【新闻】页面。
在上面例子中修改 2 处。
1、在【账户】页面下增加【替换路由】按钮,即下面黄色底纹代码。
<button @click=“replace”>替换路由</button>
2、添加相应的方法
methods:{
replace(){
this.$router.replace({
path:‘/news’ })
}}
结果:
6.3、$router.go()跳转
当我们使用 go 方法时,我们就可以在 history 记录中向前或
者后退多少步,也就是说通过 go 方法你可以在已经存储的 history路由历史中来回跳。
// 在浏览器记录中前进一步,等同于 history.forward()
this.$router.go(1)//下一页
// 后退一步记录,等同于 history.back()
this.$router.go(-1)//上一页
// 前进 2 步记录
this.$router.go(2)
// 如果 history 记录不够用,会导致失败
this.$router.go(-60)
this.$router.go(60)
6.3、$ router 与$ route 的区别
(1)$router : 是路由操作对象,实例对象,只写对象,比如:
添加路由$router.push({ path: ‘/account/login’ });
替换路由$router.replace({ path: ‘/news’ })
(2)$route : 路由信息对象,只读对象。比如:
获取路由的路径$route.path;
获取 param 方式传递的参数$route.params.name
获取 query 方式传递的参数$route.query.name
七、命名路由和命名视图
7.1、命名路由
在某些时候,我们期望生成的路由 URL 地址可能会很长,在使用中可能会显得有些不便。这时候通过一个名称来标识一个路由会更方便一些,因此在 Vue Router 中,我们可以在创建 Router 实例的时候,通过在 routes 配置中给某个路由设置名称,从而方便的调用路由。如:
const router = new VueRouter({
routes: [
{
path: ‘/aaa/bbb/about’,
name: ‘about’,
component: ‘<div>about 组件</div>’ }
]
})
当我们使用命名路由之后,当需要使用 router-link 标签进行跳转时,就可以采取给 router-link 的 to 属性绑定一个对象的方式,跳转到指定的路由地址上。如:
<router-link :to=“{ name: ‘about’}”>关于我们</router-link>
7.2、命名视图
当我们打开一个页面时,整个页面可能是由多个 Vue 组件所构成的,例如,我们的后台管理首页可能是由 sidebar (侧导航) 、header(顶部导航)和 main (主内容)这三个 Vue 组件构成的。此时,当我们通过 Vue Router 构建路由信息时,如果一个 URL 只能对应一个 Vue 组件,整个页面肯定是无法正确显示的。
通过 router-view 标签,我们就可以指定组件渲染显示到什么位置。因此,当我们需要在一个页面上显示多个组件的时候,就需要在页面中添加多个的 router-view 标签。
那么,是不是可以通过一个路由对应多个组件(这不可以),然后按需渲染在不同的 router-view 标签上呢?默认情况下不能,当我 们 将 一 个 路 由 信 息 对 应 到 多 个 组 件 时 , 不 管 有 多 少 个 的router-view 标 签 , 程 序 都 会 将 第 一 个 组 件 渲 染 到 所 有 的router-view 标签上。
那怎么办呢?我们需要实现的是一个路由信息可以按照我们的需要去渲染到页面中指定的 router-view 标签上,需要通过VueRouter 命名视图的方式实现我们的需求。
命名视图,与命名路由的实现方式相似,命名视图通过在
router-view 标签上设定 name 属性,之后,在构建路由与组件的对应关系时,以一种 name:component 的形式构造出一个组件对象,从而指明是在哪个 router-view 标签上加载什么组件。注意,这里在指定路由对应的组件时,使用的是 components(包含 s)属性进行配置组件
通过样式控制三个 router-view 的布局 :
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="js/vue.js"></script>
<script src="js/vue-router.js"></script>
<style>
.container {
height: 500px;
}
.top {
background-color: beige;
width: 100%;
height: 80px;
}
.left {
float: left;
width: 20%;
height: 100%;
background-color: burlywood;
}
.right {
float: left;
width: 80%;
height: 100%;
background-color: aquamarine;
}
</style>
</head>
<body>
<div id="app">
<div class="top">
<!-- 在 router-view 中,默认的 name 属性值为 default -->
<router-view></router-view>
</div>
<div class="container">
<div class="left">
<router-view name="sidebar"></router-view>
</div>
<div class="right">
<router-view name="main"></router-view>
</div>
</div>
</div>
</div>
<template id="sidebar">
<div class="sidebar">
sidebar
</div>
</template>
<script>
// 1、定义路由跳转的组件模板
const header = {
template: '<div class="header"> header </div>'
}
const sidebar = {
template: '#sidebar'
}
const main = {
template: '<div class="main"> main </div>'
}
const routes = [
{
path: '/',
components: {
default: header,
sidebar: sidebar,
main: main
}
}
]
const router=new VueRouter({
// routes:routes
routes //ES6语法
})
var vm = new Vue({
el: "#app",
data: {
},
//注入路由
// router: router
router
})
</script>
</body>
八、如何实现组件与路由间的解耦
在前面所讲路由传递参数的方法中,不管是 query 传参还是
param 传参,最终我们都是通过 this.$route 属性获取到参数信息,如: $route.query.name 或$route.params.name
这无疑意味着组件和路由耦合到了一块,所有需要获取参数值的地方都需要加载 Vue Router,这其实是很不应该的,因此如何实现组件与路由间的解耦呢?
在之前学习组件相关的知识时,知道可以通过组件的 props 选项来实现子组件接收父组件传递的值。而在 Vue Router 中,可以通过使用组件的 props 选项来进行组件与路由之间的解耦。下面介绍 props 三种使用情况进行解耦
8.1、设置 props:true 情况
总结:
props: [‘id’],
path: ‘/myRouter/:id’
this.$router.push({
path: ‘/myRouter/123’
})
在下面的示例中,在定义路由模板时,我们通过指定需要传递的参数为 props 选项中的一个数据项,之后,我们通过在定义路由规则时,指定 props 属性为 true,即可实现对于组件以及 VueRouter 之间的解耦。
<style>
.container {
background-color: blanchedalmond;
margin-top: 10px;
width: 600px;
height: 300px;
}
</style>
<body>
<div id="app">
<button type="button" @click="goMethod">路由与组件解
绑示例</button>
<div class="container">
<router-view></router-view>
</div>
</div>
<script>
//定义组件
const mycomp = {
props: ['id'],
template: '<h3>组件获取到了路由传递的参数:{
{id}},但此处并没有通过$route 去获取。 </h3> ' //此处没有通过$route.params.id 方式获取参数 id,也就不需要 router 实例
}
//实例化路由
const router = new VueRouter({
routes: [{
//定义路由规则
path: '/myRouter/:id', //路由规则通过占位符指明传递的参数为 id,同时 id 要为上面组件 props 选项有的值
component: mycomp,
props: true //此处 props 要设置为 true,即可以实现组件与 Vue Router 之间的解耦
}]
})
const vm = new Vue({
el: '#app', data: {
},
methods: {
goMethod() {
//该方法实现路由跳转,跳转到 myRouter,并传入参数 123
this.$router.push({
path: '/myRouter/123' //param 方式传参
})
}
},
router
})
</script>
</body>
结果:
说明: 这里采用 param 传参的方式进行参数传递,而在组件中 我们并没有加载 Vue Router 实例,也完成了对于路由参数的获取。 需要注意的是,该方法实现组件与路由的解耦,要求路由传参方式为 一定为 param 方式。针对定义路由规则时,指定 props 属性为 true 这一种情况, 在 Vue Router 中,我们还可以给路由规则的 props 属性定义成一 个对象或是函数。
8.2、设置 props 为对象情况
总结:
这里有两种方式传参,但是这里真正传过去的第一种
props: [‘id’]//存放接受传进来的参数(组件获取到的是这里的值)
props: {
id: ‘123’ //将参数传进去(组件获取到的是这里的值)
}
path: ‘/myRouter/:id’
this.$router.push({
path: ‘/myRouter/123456’//param 方式传参,随便写参数,但是必须有
})
这上面的实际获取的是123,你传参123456这里是不会接受的
<style>
.container {
background-color: blanchedalmond;
margin-top: 10px;
width: 600px;
height: 300px;
}
</style>
<body>
<div id="app">
<button type="button" @click="goMethod">路由与组件解绑示例 2</button>
<div class="container">
<router-view></router-view>
</div>
</div>
<script>
//定义组件
const mycomp = {
props: ['id'],
template: '<h3>组件获取到了路由传递的参数:{
{id}},但此处并没有通过$route 去获取。 </h3> ' //此处没有通过 $route.params.id 方式获取参数 id,也就不需要 router 实例
}
//定义路由
const router = new VueRouter({
routes: [{
//定义路由
path: '/myRouter/:id', //路由规则通过占位符指明传递的参数为 id,同时 id 要为上面组件 props 选项中有的值
component: mycomp,
props: {
id: '123' //组件获取到的是这里的值
}
}]
})
const vm = new Vue({
el: '#app', data: {
}, methods: {
goMethod() {
//该方法实现路由跳转,跳转到 myRouter
this.$router.push({
path: '/myRouter/123456'//param 方式传参,随便写参数,但是必须有
})
}
}, router
})
</script>
</body>
结果:
说明:在将路由规则的 props 定义成对象后,此时不管路由参 数中传递是任何值,最终获取到的都是对象中的值。同时,需要注意 的是,props 中的属性值必须是静态的【写死】。
8.3、设置 props 为函数情况
总结:
props: [‘id’, ‘name’]
props: (route) => ({
id: route.query.id,//获取到通过路由传递的参数,这个就是动态的
name: ‘zhangsan’//这个是静态的
})
goMethod() { //该方法实现路由跳转,跳转到 myRouter
this.$router.push({
path: ‘/myRouter?id=123’
})
}
这个只是负责跳转页面顺便传参将id的值传过去,上面的name和这里的id传的方法是不一样的。
在对象模式中,我们只能接收静态的 props 属性值,而当我们使用函数模式之后,就可以对静态值做数据的进一步加工或者是与路由传参的值进行结合。
<style>
.container {
background-color: blanchedalmond;
margin-top: 10px;
width: 600px;
height: 300px;
}
</style>
<body>
<div id="app">
<button type="button" @click="goMethod">路由与组件解绑示例 3</button>
<div class="container">
<router-view></router-view>
</div>
</div>
<script>
//定义组件
const mycomp = {
props: ['id', 'name'],
template: '<h3>组件获取到了路由传递的参数:
{
{
id } }——{
{
name } },但此处并没有通过$route 去获取。 </h3 > ' //此处没有通过$route.params.id 方式获取参数 id,也就不需要 router 实例
}
//定义路由
const router = new VueRouter({
routes: [{
//定义路由
path: '/myRouter',
component: mycomp,
props: (route) => ({
id: route.query.id,//获取到通过路由传递的参数,这个就是动态的
name: 'zhangsan'//这个是静态的
})
}]
})
const vm = new Vue({
el: '#app',
data: {
//msg:‘987’
},
methods: {
goMethod() {
//该方法实现路由跳转,跳转到 myRouter
this.$router.push({
path: '/myRouter?id=123'//这要求 query 方式传参
//path: '/myRouter?id='+this.msg//这要求 query 方式传参,动态参数
})
}
}, router
})
</script>
</body>