这章非常重要哈,编程编程编程。随缘上代码
导读:
本章重点
- 了解vue-router的实现原理
- 熟练路由的安装与使用
- 掌握路由对象的常用属性和动态路由的匹配及路由嵌套的方法
- 掌握命名路由、命名视图和编程式导航及query、params传参方式的方法
1.初识路由
路由:决定数据包从源地址到目的地址的路径;
转发:将源地址的数据转送到目的地址。
关键技术:路由表(映射表),决定数据包的指向。
Vue中的路由,用不同的URL对应不同的内容。
01什么是后端路由
例如:早期的网站开发,HTML页面由服务器直接渲染。
一个网站,那么多页面服务器如何处理呢? 每个页面有自己对应的网址(URL)
工作原理:
后端路由通过用户请求的URL分发到具体的处理程序,浏览器每次跳转到不同的URL,都会重新访问服务器。服务器收到请求后,将数据和模板组合,返回HTML页面,或者直接返回HTML模板,由前端JavaScript程序再去请求数据,使用前端模板和数据进行组合,生成最终的HTML页面。 (这个过程中会有一定的网络延迟)
优点:
渲染好的页面,不需要单独加载任何的JS和CSS,可以直接交给浏览器展示,有利于SEO(搜索引擎优化)
缺点:
- 对开发人员要求较高,需要同时具备前后端能力;
- HTML代码和数据,以及对应的逻辑会混在一起, 编写和维护都较复杂。
02什么是前端路由
前端路由就是把不同路由对应不同的内容或页面的任务交给前端来做。核心是改变URL,但是页面不进行整体的刷新。
例如:单页面富应用(SPA),就是在前后端分离的基础上加了一层前端路由实现的。
工作原理:
前端路由在访问一个新页面的时候仅仅是变换了一下hash值而已,没有和服务端交互,所以不存在网络延迟,提升了用户体验。
2.Vue-router
目前前端流行的三大框架, 都有自己的路由实现:
- Angular的ngRouter
- React的ReactRouter
- Vue的vue-router
vue-router是Vue官方推出的路由管理器,和vue.js是深度集成的,适合用于构建单页面应用(https://router.vuejs.org/zh/)。
其主要用于管理URL,实现URL和组件的对应,以及通过URL进行组件之间的切换,从而使构建单页面应用变得更简单。
01vue-router工作原理简介
vue-router基于路由和组件:路由用于设定访问路径,将路径和组件映射起来。
在vue-router的单页面应用中, 页面的路径的改变就是组件的切换。
根据mode参数,单页面前端路由有两种实现方式:
- hash模式;
- history模式。
02vue-router工作原理:hash模式和history模式
1.hash模式
vue-router默认为hash模式。
hash模式使用URL的hash来模拟一个完整的URL,根据hash值的不同,渲染指定DOM位置的不同数据。
#就是hash符号(哈希符或者锚点),在hash符号后的值,称为hash值。
利用window可以监听onhashchange事件来实现hash模式。
- hash值是用来指导浏览器动作的,对服务器没有影响;
- HTTP请求中不包括hash值;
- 每一次改变hash值,都会在浏览器的访问历史中增加一个记录,使用“后退”按钮,就可以回到上一个位置。
2.history模式
history模式不会出现#号,比较美观。
利用history.pushState()来完成URL的跳转,而且无须重新加载页面。 使用history模式时,需要在路由规则配置中增加mode:'history'。
#示例代码
// main.js文件
const router = new VueRouter({
mode: 'history',
routes: [...]
})
HTML5中history有两个新增的API,分别是history.pushState() 和 history.replaceState(),它们都接收3个参数,即状态对象(state object)、标题(title)和地址(URL)。
03vue-router使用案例
- 下载并引入vue.js和vue-router.js文件
需要从官方网站获取vue.js和vue-router.js文件,保存到文件目录中。其次创建html文件,并在文件中引入这两个文件,示例代码如下。
<script src="vue.js"></script>
<script src="vue-router.js"></script>
注意引入顺序: 在引入vue-router.js之前,必须先引入vue.js,因为vue-router需要在全局Vue的实例上挂载vue-router相关的属性。
var login = { // 创建组件
template: '<h1>登录组件</h1>'
}
var routerObj = new VueRouter({[ // 配置路由匹配规则
routes: {path: '/login', component: login} ]
})
var vm = new Vue({
el: '#app',
router: routerObj // 将路由规则对象注册到vm实例上
})
vue-router可以实现当用户单击页面中的A按钮时,页面显示内容A;单击B按钮时,页面显示内容B。即用户单击的按钮和页面显示的内容之间是映射的关系。
vm.$route:当前活动路由,
vm.$router.options.routes,路由组
vm.$router:路由机制
路由中3个基本的概念:
route、routes、router。
route :
是一条路由,单数形式。如“A按钮=>A内容”表示一条route,”B按钮=>B内容”表示另一条route。
routes:
是一组路由,把route的每一条路由组合起来,形成一个数组。如“[{A按钮=>A内容},{B按钮=>B内容}]”。
router:
是一个机制,充当路由管理者角色。当用户单击A按钮的时候,router需要到routes中去查找对应的A内容,然后在页面中显示出A内容。
在创建的routerObj对象中,如果不配置mode,就会使用默认的hash模式,该模式下会将路径格式化为#开头。
添加mode:'history'之后,将使用HTML5 history模式,该模式下没有#前缀。component的属性值,必须是一个组件的模板对象,不能是组件的引用名称。
04路由对象属性
路由对象(route object)表示当前激活的路由的状态信息,包含了当前URL解析得到的信息,还有URL匹配到的路由记录。
路由对象是不可变的,每次成功地导航后都会产生一个新的对象。
路由对象$route(当前正在用于跳转的路由器对象(处于活跃态的路由))。 常用属性信息如下表。
属性名 |
类型 |
说明 |
$route.path |
String |
对应当前路由的名字 |
$route.query |
Object |
一个{key:value}对象,表示 URL查询参数 |
$route.params |
Object |
一个{key:value}对象,路由转跳携带参数 |
$route.hash |
String |
在history模式下获取当前路由的hash值(带#),如果没有hash值,则为空字符串 |
$route.fullPath |
String |
完成解析后的URL,包含查询参数和hash的完整路径 |
$route.name |
String |
当前路由的名称 |
$route.matched |
Array |
路由记录,当前路由下路由声明的所有信息,从父路由(如果有)到当前路由为止 |
$route.redirectedFrom |
String |
如果存在重定向,即为重定向来源的路由 |
this.$router:
表示全局路由器对象
3.熟悉路由的安装和使用—用户登录注册案例
掌握如何动手搭建一个webpack+Vue项目,掌握相关loader的安装与使用,包括css-loader、style-loader、vue-loader、url-loader、sass-loader等,熟悉webpack的配置、文件的打包,以及路由的配置及使用。
01案例分析
02准备工作
创建C:\vue\chapter05\login目录,在命令行中切换到该目录,执行以下命令。
npm init –y // 选项“-y”表示全部使用默认
执行完上述代码,会在login目录下自动生成一个package.json工程文件(项目依赖、名称、配置),会记录需要的依赖包。另外,读者也可以省略选项“-y”,此时程序会提示输入项目的一些基本信息。
在login目录下执行如下命令,安装vue和vue-router。
npm install vue@2.6.x vue-router@3.1.x
安装完成之后,会在当前目录下自动生成一个package-lock.json文件。
项目中需要打包文件,所以需要用到webpack打包工具,实现自动打包编译功能。为了更方便地使用webpack,还需要安装webpack-cli工具、webpack-dev-server服务器和html-webpack-plugin插件。具体安装命令如下:
npm install webpack@4.39.x webpack-cli@3.3.x webpack-dev-server@3.8.x
html-webpack-plugin@3.2.x -D
上述命令中,-D表示安装到本地开发依赖,也可以使用--save-dev来代替。
接下来修改package.json文件,在scripts中添加dev,使用webpack-dev-server来启动项目,具体代码如下。
"scripts": {
……(原有代码),
"dev": "webpack-dev-server --inline --hot --port 8088"
},
添加上述代码后,当需要运行项目时,可以执行npm run dev命令。
创建webpack.config.js文件,在文件中配置webpack的选项,设置入口文件、出口文件以及一些规则配置,具体代码如下:
const htmlWebpackPlugin = require('html-webpack-plugin')
在build文件夹会生成一个index.html文件和一个bundle.js文件,而且index.html文件中自动引入webpack生成的bundle.js文件。所有这些都使html-webpak-plugin的功劳。
- 安装vue-loader和vue-template-compiler
vue-loader作用是解析和转换vue文件,提取出其中的script、style、HTML、template,然后分别把它们交给各自相对应的loader去处理。vue-template-compiler的作用是把vue-loader提取出的HTML模板编译成对应的可执行的JavaScript代码。
具体命令如下:
npm install vue-loader@15.7.x vue-template-compiler@2.6.x -D
安装后,将vue-loader插件添加到webpack.config.js文件中,示例代码如下。
const VueLoaderPlugin = require('vue-loader/lib/plugin')
module.exports = {
……
plugins: [
……
new VueLoaderPlugin()
]
}
然后在module.exports 中找到module,在rules数组中配置loader加载依赖。
module: {
rules: [
{
test: /\.vue$/, //正则表达式
use: 'vue-loader'
},
// 在此处可以添加更多rules
]
},
- 安装css-loader和style-loader
css-loader和style-loader用来处理样式文件。css-loader用于加载由vue-loader提取出的CSS文件,再用style-loader添加到页面中。具体安装命令如下。
npm install vue-loader@15.7.x vue-template-compiler@2.6.x -D
安装后,在webpack.config.js文件中添加rules规则,具体代码如下。
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
通过CSS预处理器可以使用专门的编程语言来编写页面的样式,然后编译成正常的CSS文件,供项目使用。CSS预处理器为CSS增加了一些编程的特性,用户无须考虑浏览器的兼容性问题,可以使CSS更加简洁、更具有适用性和可读性,更易于代码的维护。
Vue中常用的CSS预处理器包括Less、Sass/SCSS和Stylus,下面我们分别讲解如何进行安装。需要注意的是,在本项目中只用到了Sass/SCSS,必须进行安装,而另外两个CSS预处理器读者可根据自己的需要来决定是否安装。
安装Less,具体命令如下。
npm install less less-loader -D
然后在webpack.config.js文件中添加rules规则,具体代码如下。
{
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader']
},
安装后,在页面中使用Less的地方给<style>添加lang属性即可,示例代码如下。
<style lang="less"></style>
安装Sass/SCSS,具体命令如下。
npm install sass-loader@7.2.x node-sass@4.12.x -D
然后在webpack.config.js文件中添加rules规则,具体代码如下。
{
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader']
},
安装后,在页面中使用SCSS的地方给<style>添加lang属性即可,示例代码如下。
安装Stylus,具体命令如下。
npm install stylus stylue-loader -D
Stylus是一款 CSS 的预处理器,即 CSS 框架。由于来源于Node.js社区,与JS关系比较密切。安装完成之后,在Vue 2.x中不需要配置就可以直接使用,在页面中使用Stylus的地方给<style>添加lang属性即可,示例代码如下。
<style lang="stylus"></style>
将MUI安装后,可以在main.js文件中使用如下代码引入。
import './lib/mui/css/mui.css'
安装file-loader和url-loader,具体命令如下。
npm install url-loader@2.1.x file-loader@4.2.x -D
然后在webpack.config.js文件中添加rules规则,具体代码如下。
{
test: /\.(jpg|png|gif|bmp|jpeg)$/,
use: 'url-loader'
},
{
test: /\.(ttf|eot|svg|woff|woff2)$/,
use: 'url-loader'
},
03代码实现
创建首页index.html文件,用来展示页面,具体代码如下。
<body>
<div id="app"></div>
</body>
创建逻辑入口main.js文件,该文件是逻辑入口,主要用来初始化Vue实例并加载需要的插件及各种公共组件,如vue-router、mui、App.vue等,具体代码如下。
import Vue from 'vue' // 引入vue.js
import app from './App.vue' // 引入App.vue组件
import VueRouter from 'vue-router' // 引入router. js组件
Vue.use(VueRouter) // 安装vue-router路由模块
import router from './router.js' // 将路由放到单独的文件中
import './lib/mui/css/mui.css' // 使用MUI
new Vue({ // 初始化Vue实例
el: '#app', // 将el挂载到index.html文件的<div id="app">
render: c => c(app), // 使用render函数渲染App.vue组件
router // 将router.js文件中导出的router对象注册到Vue实例上
})
创建router.js文件,该文件是一个单独的路由文件。在后面的步骤中将会创建Login.vue(登录)和Register.vue(注册)两个组件,所以需要在路由文件中导入这两个组件,并配置相应的路由规则。具体代码如下。
import VueRouter from 'vue-router'
// 导入登录和注册对应的路由组件
import Login from './components/Login.vue'
import Register from './components/Register.vue'
var router = new VueRouter({ // 创建路由对象
routes: [ // 配置路由规则
{ path: '/', redirect: '/login' }, //重定向
{ path: '/login', component: Login },
{ path: '/register', component: Register }
]
})
export default router
router-link-exact-active和router-link-active两者的区别在于,前者是精确匹配规则,只有完全匹配的情况下有效,而后者是非精确匹配规则,只要定义在path中的路径与当前路径的开头一致就有效。如:”/login”和”/login?name=a”
另外,router-link-exact-active和router-link-active这两个class类名也可以自定义,下面在router.js文件中找到创建路由实例代码,添加自定义class,具体代码如下。
var router = new VueRouter({
linkActiveClass: 'my-active', // router-link-active
linkExactActiveClass: 'my-exact-active', // router-link-exact-active
……(原有代码)
})
然后在App.vue中添加导航栏高亮效果的样式,具体代码如下
<style lang="scss" scoped>
.my-active, .my-exact-active {
background: #007aff;
font-weight: 800;
color: #fff;
}
……(原有代码)
</script>
在浏览器中查看运行结果,页面效果如下图所示。
创建App.vue文件,该文件是项目的根组件(或者叫作主组件),所有页面都是在App.vue下进行切换的。例如,可以定义公共的样式或者动画等。具体代码如下。
<template>
<div id="app">
<div class="login-container">
<router-link to="/login" tag="span">登录</router-link>
<router-link to="/register" tag="span">注册</router-link>
</div>
<router-view></router-view>
</div>
</template>
<style lang="scss" scoped></style>
// scoped表示CSS样式只能作用于当前的组件
创建components\Login.vue文件,该文件是登录页面,在页面中提供一个用户登录的表单。具体代码如下。
<template>
<div class="login">
<div class="content">
<form class="mui-input-group login-form">
<div class="mui-input-row"><label>账号</label><input></div>
<div class="mui-input-row"><label>密码</label><input></div>
</form>
<div><button type="button">登录</button></div>
</div>
</div>
</template>
<style scoped></style>
上述代码可以看出,一个单独的组件文件通常应包含<template>模板、<script>逻辑以及<style>样式3部分代码。其中,<script>和<style>可以省略,但<template>不要省略,否则Vue会出现警告。
创建components\Register.vue文件,该文件是注册页面,在页面中提供一个用户注册的表单。具体代码如下。
#注册界面
<template>
<div class="register">
<div class="content">
<form class="mui-input-group login-form">
<div class="mui-input-row">
<label>账号</label>
<input type="text" class="mui-input-clear mui-input" placeholder="请输入账号">
</div>
<div class="mui-input-row">
<label>密码</label>
<input type="password" class="mui-input-clear mui-input" placeholder="请输入密码">
</div>
<div class="mui-input-row">
<label>密码确认</label>
<input type="password" class="mui-input-clear mui-input" placeholder="请确认密码">
</div>
<div class="mui-input-row">
<label>邮箱</label>
<input type="password" class="mui-input-clear mui-input" placeholder="请输入邮箱">
</div>
</form>
<div class="mui-content-padded">
<button type="button" class="mui-btn mui-btn-block mui-btn-primary">注册</button>
</div>
</div>
</div>
</template>
在命令行中切换到项目根目录下,执行如下命令运行程序
npm run dev
当控制台中出现Compiled successfully时表示编译完成,项目已经启动了,然后在浏览器中打开http://localhost:8088,页面效果如下图所示。
在上图中,单击顶部的“登录”和“注册”可以在两个页面之间切换,但由于此时还没有设置样式,导航栏并没有高亮效果。默认情况下,路由的导航菜单会自动添加router-link-exact-active和router-link-active这两个class属性,想要设置导航栏的高亮效果,只要在App.vue文件中设置两个class对应的样式即可,如下图所示。
路由的history模式可以使项目的URL地址更加简洁。若要使用history模式,需要先修改router.js文件,具体代码如下。
var router = new VueRouter({
mode: 'history', // 使用history模式
……(原有代码)
}
history模式还需要服务器的支持,打开webpack.config.js文件,在module.exports对象中添加devServer的配置,具体代码如下。
devServer: {
historyApiFallback: true // 开启服务器对history模式支持
},
当开启history模式后,重新执行npm run dev,就可以使用http://localhost:8088/login来访问登录页面,使用http://localhost:8088/register来访问注册页面。
当页面切换后,网页的标题也应随之发生变化,为了实现这个效果,可以在路由中将每个页面对应的标题保存在meta中。修改router.js文件,如下所示。
routes: [
{ path: '/', redirect: '/login' },
{ path: '/login', component: Login, meta: { title: '登录' } },
{ path: '/register', component: Register, meta: { title: '注册' } }
]
然后需要调用router.beforeEach()全局钩子函数,用来在路由发生改变时动态修改网页的title标题,它会在路由改变前执行。具体代码如下。
router.beforeEach((to, from, next) => {
// 路由发生改变修改页面title
if (to.meta.title) {
document.title = to.meta.title
}
next()
})
4.动态路由
01什么是动态路由
在vue-router的路由路径中,可以使用动态路径参数给路径的动态部分匹配不同的id,示例代码如下。
{ path: "/user/:id", component: user }
:id表示用户id,动态值
动态路由在来回切换时,由于它们都是指向同一组件,Vue不会销毁再重新创建这个组件,而是复用这个组件。
如果想要在组件来回切换时进行一些操作,那就需要在组件内部利用watch来监听$route的变化,示例代码如下。
watch: {
$route (to, from) {
console.log(to) // to表示要去的那个组件
console.log(from) // from表示从哪个组件过来的
}
}
02query方式传参
通过query方式传递参数,使用path属性给定对应的跳转路径(类似于GET请求),在页面跳转的时候,可以在地址栏看到请求参数。
课件有实现过程 三步
03params方式传参
使用params方式则不需要通过查询字符串传参,通常会搭配路由的history模式,将参数放在路径中或隐藏。
在路由中开启history模式后,params方式的URL地址会更加简洁,但此功能必须搭配服务器使用,并且要在服务器中添加history模式的支持(在5.3节中已经讲过,见本PPT85页),否则会出现找不到文件的错误。
课件有实现过程
5.嵌套路由
01什么是嵌套路由
是否是嵌套路由主要是由页面结构来决定的,实际项目中的应用界面,通常由多层嵌套的组件组合而成。简而言之,嵌套路由就是在路由里面嵌套它的子路由(父子路由)。
嵌套子路由的关键属性是children,children也是一组路由,相当于前面讲到的routes,children可以像routes一样的去配置路由数组。每一个子路由里面可以嵌套多个组件,子组件又有路由导航和路由容器。
<router-link to="/父路由的地址/要去的子路由"></router-link>
02嵌套路由的案例
6.命名路由
01什么是命名路由
vue-router提供了一种隐式的引用路径,即命名路由,可以在创建Router实例的时候,在 routes 中给某个路由设置名称name值。通过一个名称来标识一个路由显得更方便一些,特别是在链接一个路由,或者是执行一些跳转的时候,通过路由的名称取代路径地址直接使用。像这种命名路由的方式,无论path多长、多烦琐,都能直接通过name来引用,十分方便。主要用于处理长path。
02命名路由案例
7.命名视图
01什么是命名视图
在开发中,有时候想同时或同级展示多个视图,而不是嵌套展示,则可以在页面中定义多个单独命名的视图。使用<router-view>可以为视图进行命名,它主要用来负责路由跳转后组件的展示。在<router-view>上定义name属性表示视图的名字,然后就可以根据不同的name值展示不同的页面,如left、main等。如果<router-view>没有设置名字,那么默认为default。
02命名路由案例
8.编程式导航
在前面的开发中,当进行页面切换时,都是通过<router-link>来实现的,这种方式属于声明式导航。为了更方便地在项目中开发导航功能,Vue提供了编程式导航,也就是利用JavaScript代码来实现地址的跳转,通过router实例方法来实现。
01router.push()
使用router.push()方法可以导航到不同的URL地址。这个方法会向history栈添加一条新的记录,当用户单击浏览器后退按钮时,可以回到之前的URL。
在单击<router-link>时,router.push()方法会在内部调用,也就是说,单击“<route-link :to="...">”等同于调用router.push(...)方法。
router.push()方法的参数可以是一个字符串路径,或者是一个描述路径的对象。
// 先获取router实例
var router = new VueRouter()
// 字符串形式
router.push('user')
// 对象形式
router.push({ path: '/login?url=' + this.$route.path })
// 命名路由
router.push({ name: 'user', params: { userId: 123 }})
// 带查询参数 /user?id=1
router.push({ path: 'user', query: { id: '1' }})
02router.replace()
router.replace()方法和router.push()方法类似,区别在于,为<router-link>设置replace属性后,当单击时,就会调用router.replace(),导航后不会向history栈添加新的记录,而是替换当前的history记录。
03router.go()
router.go()方法的参数是一个整数,表示在history历史记录中向前或者后退多少步,类似于window.history.go()。this.$router.go(-1)相当于history.back(),表示后退一步,this.$router.go(1)相当于history.forward(),表示前进一步,功能类似于浏览器上的后退和前进按钮,相应的地址栏也会发生改变。