直接在代码中debugger,就可调试
22-29没有看
135完了!!完了@@坚持到了142 ,人… 已 。。。废!!!!!!
模范话,组件化,规范化,自动化
第一章 前端工程化与webpack
- 理解什么是前端工程化
- 了解webpack的基本用法
- 不强制要求能手动配置webpack
1-1 webpack的定义
- 概念 : webpack是前端项目工程化的具体解决方案
- 主要功能 : 提供了友好的前端模块化开发支持,以及代码压缩混淆、处理浏览器JavaScript的兼容性、性能优化等强大的功能
- 好处 : 让程序员把工作的重心放到具体功能的实现上, 提高了开发效率和项目的可维护性
- 目前Vue,React等前端项目,基本上都是基于webpack进行工程化开发的
1-2 webpack的基本使用
- 创建列表隔行变色项目
- 新建项目空白目录,并运行 npm init -y 命令,初始化包管理器配置文件
package.json
- 新建src 源代码 目录
- 新建src -> index.html 首页和是src -> index.js 脚本文件
- 初始化首页基本的结构
- 运行
npm install jquery -S
命令,安装jQuery - 通过ES6 模块化的方式导入jQuery, 实现列表隔行变色效果
安装和配置webpack
- 在项目中安装webpack
- 在终端运行如下命令,安装webpack 相关的两个包:
npm install webpack@5.42.1 webpack-cli@4.7.2 -D
- -S 是 –save 的简写
- -D 是 –save–dev的简写 : 只在开发阶段会用到的意思
- 在终端运行如下命令,安装webpack 相关的两个包:
- 在项目中安装webpack
在项目中配置 webpack
(1)在根目录中,创建名为
webpack.config.js
的webpack 配置文件, 并初始化如下的基本配置1
2
3module.exports = {
mode: 'development' //mode 用来指定构建模式,可选项 : development 和production
}(2)在package.json 的scripts节点下, 新增 dev脚本 如下:
1
2
3"scripts": {
"dev": "webpack" //script 节点下的脚本,可以通过 `npm run `执行,例如: npm run dev
}(3)在终端运行
npm run dev
命令,启动webpack进行项目的打包构建
了解mode可选值的应用场景
webpack.config.js文件中
```js
//使用Node.js的导出语法,向外导出一个webpack 的配置对象
module.exports = {//代表webpack运行的模式,可选值有两个 development 和 production // 使用production,打包时长变长,文件变小 //开发追求打包速度;使用development; 发布上线时要使用 production.因为上线追求的是体积小 mode: 'development'
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
##### 1-3 webpack的基本使用 -- 指定webpack的entry和output(自定义打包的入口和出口)
1. `npm run dev`run 脚本的时候 会先读取配置文件`webpack.config.js`,根据配置运行`index.js`
2. webpack 4.x 和 5.x的版本中,有如下 的默认约定
- 默认的打包入口文件为 `src -> index.js`
- 默认的输出文件路径为`dist -> main.js`
- 注意 : 可以在`webpack.config.js`中修改打包的默认约定
3. 在webpack.config.js 配置文件中
- 通过`entry节点`指定**打包的入口**
- 通过**output节点**指定**打包的出口**
- 示例 :
4. dist文件夹可以被删除,因为自动生成
##### 1-4 安装和配置插件
1. 通过安装和配置第三方的插件,可以拓展webpack的能力,从而让webpack用起来更方便
- `webpack-dev-server `
- 类似于node.js阶段用到的nodemon工具
- 每当修改了源代码,webpack会自动进行项目的打包和构建
- `html-webpack-plugin`
- webpack中的HTML插件(类似于一个模板引擎插件)
- 可以通过此插件自定制index.html 页面的内容
2. 安装 `webpack-dev-server`
- 运行如下的命令 : `npm install webpack-server@3.11.2 -D`
3. - 配置 package.json -> script 中的 dev 命令:
- 再次运行`npm run dev`命令,重新进行项目的打包
- 在浏览器中访问`http://localhost:8080`地址, 查看自动打包效果(放在内存里面,没有放在物理磁盘上,删除dist文件之后,ctrl+s没有生成该文件)
4. 安装`html-webpack-plugin`插件
- 运行如下代码 :`npm install html-webpack-plugin@5.3.2 -D`
5. 配置`html-webpack-plugin`
- (1)导入HTML 插件, 得到插件的构造函数
`const HtmlPlugin = require('html-webpack-plugin')`
- (2)创建HTML 插件的实例对象
```js
const htmlPlugin = new HtmlPlugin({
template: './src/index.html',//指定原文件的存放路径
filename : './index.html', //指定生成的文件的存放路径
})
module.exports = {
mode: 'development',
plugins: [htmlPlugin], //3. 通过 plugins 节点,使 htmlPlugin插件生效
}
1-5 了解 html-webpack-plugin的特性 & 了解devServer
中常用的选项
devServer节点 :
在webpack.config.js配置文件中, 可以通过 devServer 节点对webpack-dev-server 插件进行更多的配置
1
2
3
4
5devServer : {
open: true, //初次打包完成后, 自动打开浏览器
host : '127.0.0.1', // 实时打包所使用的主机地址
port: 80, // 实时打包所使用的端口号
}注意: 凡是修改了webpack.config.js配置文件, 或修改了package.json 配置文件, 必须重启实时打包的服务器,否则最新的配置文件无法生效!
1-6 webpack中的loader
loader的调用过程
loader概述:
- 在实际开发过程中, webpack默认只能打包处理.js后缀名结尾的模块。
- 其他非.js后缀名结尾的模块,webpack 默认处理不了,需要调用loader加载器才可以正常打包,否则会报错
loader 加载器的作用:协助webpack打包处理特定的文件模块
css-loader 可以打包处理.css相关的文件
less-loader 可以处理 .less相关的文件
babel-loader 可以打包处理webpack 无法处理的高级JS语法
-
1-7 打包处理css以及less文件超严重问题
打包处理css文件
运行
npm i style-loader@3.0.0 css-loader@5.2.6 -D
命令,安装处理css文件的loader在webpack.config.js的module -> rules 数组中,添加loader 规则:
1
2
3
4
5module: { //所有第三方文件模块的匹配规则
rules:[ //文件后缀名的匹配规则
{ test: /\.css$/, use: ['style-loader','css-loader']},
]
}- 其中,test表示匹配的文件类型,use表示对应要调用的loader
- 注意:(1)use数组中指定的loader顺序是固定的 (2)多个loader的调用顺序是 : 从后往前调用
(1)webpack默认只能打包处理.js结尾的文件,处理不了其他后缀的文件
(2)由于代码中包含了index.css这个文件,因此webpack默认处理不了
(3)当webpack发现某个文件处理不了的时候,会查找webpack.config.js 这个配置文件,看module.rules 数组中,是否配置了对应的loader加载器
(4)webpack把index.css这个文件,先转交给最后一个loader进行处理(先转交给css-loader)
(5) 当css-loader处理完毕之后,会把处理的结果,转交给下一个loader(转交给style-loader)
(6)当style-loader 处理完毕之后,发现没有下一个loader了,于是就把处理的结果,转交给webpack
(7)webpack把style-loader处理的结果,合并到/dist/bundle.js 中,最终生成打包好的文件
运行
npm i less-loader@10.0.1 less@4.1.1 -D
命令在文本webpack.config.js 的
module -> rules
数组中,添加loader 规则如下:
1 | module: { //所有第三方文件模块的匹配规则 |
1-8 base64的图片优缺点
1-9 演示图片loader加载的问题【依旧是bigbug】
需求 : 把 /src/images/logo.jpg 设置给 src 属性
打包处理样式表中与url路径相关 的文件
运行
npm i url-loader@4.1.1 file-loader@6.2.0 -D
命令在webpack.config.js的 module -> rules 数组中, 添加loader 规则 :
1
2
3
4
5
6module : { //所有第三方模块的匹配规则
rules: [ // 文件后缀名 的匹配规则
{test: /\.jpg|png|gif$ /, use: 'url-loader?limit-22229'},
]
}- 其中 ? 之后的是loader 的参数项
- limit用来指定图片的大小,单位是字节(byte)
- 只有 <= limit 大小的图片, 才会被转为 base64 格式的图片
第二章 了解vue是什么
2-1 Vue简介
概念 : 一套用于构建用户界面的前端框架
- 构建用户界面 : 用vue往html页面中填充数据
- 框架
- 框架是一套线现成的解决方案,程序员只能遵守框架的规范,去编写自己的业务功能
- 学习vue,就是在学习vue框架中规定的写法
- vue的指令、组件(是对UI结构的复用)、路由、Vuex、xue组件库
- 只有把上面罗列的内容掌握,才有开发vue项目的能力
vue框架的特性:
- 数据驱动视图(单向的数据绑定),数据的变化会驱动视图自动更新
vue监听数据的变化,自动操作dom元素
双向数据绑定
- 在网页中。form表单负责采集数据,ajax负责提交数据
- js数据的变化,会被自动渲染到页面上
- 页面上表单采集的数据发生变化时,会被vue自动获取到,并更新到js数据中
2-2 MVVM
MVVM是vue实现数据驱动视图和双向数据绑定的核心原理
MVVM指的是Model,View和 ViewModel
MVVM将HTML页面拆分成三部分
ViewModel 作为 MVVM的核心, 是它把当前页面的数据源(Model)和页面的结构(View)连接在一起
- 当数据源发生变化时,会被ViewModel监听到,VM会根据最新的数据源自动更新页面的结构
- 当表单元素的值发生变化时,也会被VM监听到,VM会把变化后最新的值自动同步到Model数据源中
2-3 vue版本
- vue有三大版本
- 2.x版本的vue是目前企业级项目开发中的主流版本
- 3.x版本的vue于2021-09-19 发布,生态还未完善,尚未在企业级项目开发中普及和推广
- 1.x 版本的vue几乎被淘汰
- 总结 :
- 3.x版本的 vue 是未来企业级项目开发的趋势
- 2.x版本的vue在未来会被逐渐淘汰
2-4 vue的基本使用— 内容渲染指令
基本使用步骤
导入vue.js 的script脚本文件
在页面中声明一个将要被Vue所控制的DOM区域
创建vm实例对象(vue实例对象)
fireFox浏览器在线安装vue-devtools : https://addons.mozilla.org/zh-CN/firefox/addon/vue-js-devtools/
vue的指令与过滤器
- 指令(Directives)是vue为开发者提供的模板语法,用来辅助开发者渲染页面的基本结构
- vue中的指令按照不同的用途分为六大类:
- 内容渲染指令
- 属性绑定指令
- 事件绑定指令
- 双向绑定指令
- 条件渲染指令
- 列表渲染指令
- 注意 :指令是vue开发中最基础、最常用、最简单的
内容渲染指令 :
用来辅助开发者渲染DOM元素的文本内容
v-text 指令 :会覆盖元素内默认的值!!
- ```js
性别
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
- {{}}语法 : **插值表达式**(Mustache语法)
- **只能用在内容节点,不能用在元素的属性节点**
- v-html :
- 前面两个标签无法将html元素渲染到页面上,只能是普通的字符串
- 指令的作用 : 可以把带有标签的字符串,渲染成真正的HTML内容
5. 属性绑定指令 :
> 注意 : **插值表达式**(Mustache语法)**只能用在内容节点,不能用在元素的属性节点**
- 需要为元素的***属性**动态绑定属性值,则需要用到**v-bind 属性**绑定指令,<font color=red> 简写是英文的 `:`</font>
6. 事件绑定指令 :
- vue提供了 v-on 事件绑定 指令,用来辅助程序员为 DOM元素绑定事件监听,<font color=red> 简写是@,简写:`add : function(){}, 写成 add(){}`</font>
- 注意: 原生DOM对象有`onclik` ,`oninput`,`onkeyup`等原生事件,替换为vue的事件绑定形式之后,分别为: `v-on:click`,`v-on:input`,`v-on:keyup`
- 事件绑定: $event
- `<button @click=add($event, 1)>+N</button>`
- 事件绑定----事件修饰符 : 在事件处理函数中调用`event.preventDefault()`或`event.stopPropagation()`是非常常见的需求
- 事件修饰符的提出,辅助程序员对事件的触发进行控制
- 常见的5个事件修饰符如下 :
| 事件修饰符 | 说明 |
| ---------- | --------------------------------------------------- |
| .prevent | 阻止默认行为(例如:阻止a链接的跳转) |
| .stop | 阻止事件冒泡 |
| .capture | 以捕获模式触发当前的事件处理函数 |
| .once | 绑定的事件只触发一次 |
| .self | 只有在event.target 是当前元素自身时触发事件处理函数 |
- 事件绑定 --- 按键修饰符
- 在监听**键盘事件**时,我们经常需要**判断的详细的按键**。此时,可以为**键盘相关的事件**添加**按钮修饰符**
```js
<body>
<div class="app">
<input type="text" @keyup.esc="clearInput" @keyup.enter="commitAjax">
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
// 创建 Vue 的实例对象
const vm = new Vue({
el: '.app',
data: {},
methods: {
clearInput(e) {
console.log('触发了');
e.target.value = '';
},
commitAjax() {
console.log('我触发了');
}
}
})
</script>
</body>
- ```js
双向绑定指令
vue 提供了
v-model 双向数据绑定
指令,用来辅助开发者不操作DOM的前提下, 快速获取表单的数据适用于(输入进来的均为字符串):
为了方便对用户输入的内容进行处理, vue为v-model 指令提供了3个修饰符
修饰符 作用 示例 .number 自动将用户的输入值转为数值类型 <input v-model.number="age">
.trim 自动过滤用户输入的首尾空白字符 <input v-model.trim="msg"/>
.lzy 在”change“时而非”input“时更新 <input v-model.lazy="msg"/>
条件渲染指令 : 辅助开发者按需控制DOM的显示和隐藏
v-show原理: 动态为元素添加或移除
display : none
样式,来实现元素的显示与隐藏- 频繁切换元素的显示状态,用v-show性能更好
v-if的原理 : 每次动态创建或移除元素,实现元素的显示和隐藏
- 如果刚进入页面,某些元素默认不需要被展示, 而且后期这个元素很可能也不需要被展示出来,此时v-if性能更好
- v-if配套指令
列表渲染指令
vue提供了v-for列表渲染指令, 用来辅助开发者基于一个数组来渲染一个列表结构。
- v-for 指令需要使用 item in items 形式的特殊语法
- items 是待循环的数组
- item 是 被数组循环的每一项
v-for 指令还支持一个可选的第二个参数, 即当前项的索引。语法格式为 (item, index) in items
- v-for 指令中的 item项和 index 索引都是形参, 可以根据需要进行 重命名。 例如 :
(user, i) in userlist
- v-for 指令中的 item项和 index 索引都是形参, 可以根据需要进行 重命名。 例如 :
2-5 el属性的使用注意点以及使用javscript 表达式
如果el只挂载一个p标签,vue只控制第一个p标签
在vue提供的模板渲染语法中, 除了支持绑定简单的数据值之外,还支持Javascript表达式的运算
1
2
3
4
5{{ number + 1 }}
{{ ok ? 'YES' : 'NO'}}
{{ message.split('').reverse().join('') }}
<div v-bind:id="'list-' +id"></div>
第三章 过滤器 &侦听器 & 计算属性
3-1 过滤器的基本用法
过滤器(Filters)是vue为开发者提供的功能, 常用于文本的格式化,用在两个地方:
- 插值表达式
- v-bind 属性绑定
过滤器应该被添加在JavaScript 表达式的尾部,由 “管道符”进行调用,示例代码 :
1
2
3
4
5
6<!-- 在双花括号中通过”管道符“调用 capitalize 过滤器,对message 的值进行格式化 --!>
<p>{{ message | capitalize }}</p>
<!-- 在v-bind 中通过”管道符“调用 formatId 过滤器,对 rawId 的值进行格式化 --!>
<div v-bind:id="rawId | formatId"></div>
3-2 私有过滤器和全局过滤器
上面的是私有过滤器
- 定义在Vue实例里面的过滤器是私有过滤器
使用Vue.filter定义全局过滤器
在filter 节点下定义的过滤器,称为”私有过滤器“,因为它只能在当前vm实例所控制的el区域内使用
如果希望在多个vue实例之间共享过滤器,则可以按照如下的格式定义全局过滤器
1
2
3
4
5
6
7//全局过滤器 - 独立于每个vm实例之外
// Vue.filter() 方法接收两个参数:
- 第一个参数: 是全局过滤器的”名字“
- 第二个参数: 是全局过滤器的”处理函数“
Vue.filter('capitalize',(str) => {
return str.charAt(0).toUpperCase() +str.slice(1) + '~~'
})如果全局过滤器和私有过滤器名字一致,此时按照就近原则,调用的是“私有过滤器
1-3 过滤器的其他用法
过滤器可以串联进行调用,得到的结果是最后一个过滤器返回的值,用竖线连续调用多个过滤器
<td>{{ item.time | dateFormat |xxx|yyy|zzz}}</td>
过滤器的本质是JavaScript 函数,因此可以接收函数
1
2
3
4
5
6
7
8
9<!-- arg1 和 arg2 是传递给 fileterA的参数 -->
<p>{{ message | filterA(arg1, arg2)}}</p>
// 过滤器处理函数的形参列表中
// 第一个参数 : 用软都是“管道符”前面待处理的值
// 从第二个参数开始, 才是调用过滤器时传递过来的 arg1 和arg2 参数
Vue.filter('filterA',(msg, arg1, arg2) => {
//过滤器的代码逻辑...
})
3-4 了解侦听器基本的语法格式
监视数据变化
watch侦听器 :
watch侦听器允许开发者监听数据的变化,从而针对数据的变化做特定的操作
```js
const vm = new Vue({el: '#app', data: { username: ''}, watch: { //监听 username 值得变化 // newVal 是“变化后得新值”,oldVal 是“变化之前得旧值” username(newVal, oldVal){ log(newVal, oldVal) } }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
3. 侦听器的格式
- 方法格式的侦听器
- 缺点 1: 无法在刚进入页面的时候,自动触发!!!
- 缺点2 :如果侦听的是一个对象, 如果对象中的属性发生了变化,不会触发侦听器!!!
- 对象格式的侦听器
- 好处: 可以通过**immediate**选项,让侦听器自动触发!
```js
watch: {
username: {
//侦听器的处理函数
handler(newVal, oldVal) {
console.log(1);
},
// 选项的默认值是false
// immediate 的作用 : 控制侦听器是否自动触发一次!
immediate: true
}
}好处2 : 可以通过deep选项, 让侦听器深度监听对象中每个属性的变化
- (如果watch侦听的是一个对象, 如果对象中的属性值发生变化,则无法被监听到, 此时需要使用deep选项)
- 如果只是想监听对象中单个属性的变化, 则可以按照如下的方式定义watch 侦听器
- deep选项
3-5 计算属性 & axios
计算属性就是通过一系列运算之后,得到的一个属性值
- 这个动态计算出来的属性值 可以被模板结构或 methods 方法使用
使用axios(艾克C奥斯)发起基本的GET请求
axios 是一个专注于 网络(数据)请求的库!
1
2
3
4
5
6
7
8
9
10
11
12axios({
//请求方式
method: 'GET',
// 请求的地址
url: 'http://www.liulongbin.top:3006/api/getbooks',
// URL 中查询参数, get传参
params: {
id: 1
},
}).then(function(result) {
console.log(result);
})发起post请求(结合 async 和 await 调用axios)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<button id="postInfo">发起POST请求</button>
<script>
document.querySelector('#postInfo').addEventListener('click', async function() {
// 如果调用某个方法的返回值是Promise实例,则前面可以添加 await
// await 只能在被 async“修饰” 的方法中
const result = await axios({
method: 'POST',
url: 'http://www.liulngbin.top:3006/api/post',
data: {
name: 'zs',
age: 20
}
})
// .then变化await
/* .then(function(result) {
console.log(result);
}) */
console.log(result);
})
</script>```js
document.querySelector(‘#btnGet’).addEventListener(‘click’, async function() {// 解构赋值的时候,使用 : 进行重命名 // 1. 调用axios 之后, 使用async/await 进行简化 // 2. 使用解构赋值, 从axios 封装的大对象中, 把data属性结构出来 // 3. 把解构出来的data属性,使用 冒号 进行重命名, 一般命名为{ data: res} const { data: res } = await axios({ method: 'GET', url: 'http://www.liulongbin.top:3006/api/getbooks', }) console.log(res.data); })
1
2
3
4
5. ```js
// $.ajax() $.get() $.post()
// axios() axios.get() axios.post() axios.delete() axios.put()
3-6 基于axios.get和axios.post发起请求
```js
<button id="btnPost">POST请求</button> <script src="../day3/lib/axios.js"></script> <script> document.querySelector('#btnGET').addEventListener('click', async function() { /* axios.get('url地址',{ //GET 参数 params :{} }) */ const { data: res } = await axios.get('http://www.liulongbin.top:3006/api/getbooks', { params: { id: 1 } }) console.log(res); }) document.querySelector('#btnPost').addEventListener('click', function() { // axios.post('url', {/* post请求体数据 */}) const { data: res } = await axios.post('http://www.liulongbin.top:3006/api/post', { name: 'zs', gender: '女' }) console.log(res); })
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
## 第四章 vue-cli
##### 4-1 介绍并安装vue-cli
1. 单页面应用程序(Single Page Application):简称SPA
- 一个Web网站中只有唯一的一个HTML页面,所有的功能与交互都在这一个页面内完成
2. 什么是vue-cli :
- vue-cli是Vue.js 开发的标准工具,简化了基于webpack 创建工具化的Vue项目的过程
3. vue-cli 是npm上的一个全局包,使用 npm install 命令, 方便于安装到自己的电脑上 `npm install @vue/cli`
- 基于vue-cli 快速生成工程化的Vue项目 :
`vue create 项目的名称`
- vue项目中src目录的构成 :
- `assets`文件夹,存放项目中用到的静态资源文件,例如 :css样式表,图片资源
- components 文件夹,程序员封装的,可复用的组件,都要放到 components目录下
- main.js 是项目的入口文件,整个项目的运行,要先执行
- 冻结 : 轻轻点一下,按ctrl+c
##### 4-2 了解vue项目的运行
1. 在工程化的项目中,vue要做的事情很单纯 : 通过**main.js** 把**App.vue** 渲染到 **index.html** 的指定区域中(把ip为app的div给替换掉)
2. - App.vue用来编写待渲染的**模板结构**
- **index.html**中需要预留一个**el区域**
- main.js把App.vue渲染到了index.html所预留的区域中
##### 4-3 组件的基本使用
1. 声明自己的模板结构,类似于app.vue
2. main.js文件中:
```js
// 导入vue这个包,得到Vue 构造函数
import Vue from 'vue'
// 导入 App.cue 跟组件,将来要把App.vue 中的模板结构,渲染到HTML 页面中
// import App from './App.vue'
import Test from './Test.vue'
Vue.config.productionTip = false
// 创建Vue的实例对象
new Vue({
//把App文件里面的UI结构渲染到el指定的区域(ip为app所在的位置)
// el: '#app', //手动指定渲染在哪里
render: h => h(Test)
}).$mount('#app') //指定app区域
//Vue实例的 $mount()方法,作用和el属性完全一样组件化开发:
定义: 根据封装的思想,把页面上可重用的UI结构封装为组件,从而方便项目的开发和维护
vue是一个支持组件化开发的前端框架
组件的后缀名:.vue。之前接触的App.vue文件本质上是一个vue的组件
vue组件的三个组成部分
- .template -> 组件的模板结构
- script -> 组件的JavaScript行为
- style -> 组件的样式
temple..只能出现一个根元素
4-4 使用组件的三个步骤
组件在被封装好之后,彼此之间是相互独立的,不存在父子关系
组件之间的父子关系
- 在使用组件的时候,根据彼此的嵌套关系,形成了父子关系,兄弟关系
使用组件的步骤:
App.vue中 : 使用import语法导入需要的组件
import Left from "@/components/Left/Left.vue"
@的配置: 在
webpack.config.js
中:1
2
3
4
5
6
7module.exports = {
resolve : {
alias: {
@:path.join(_dirname'./src')
}
}
}vue-cli已经给配置好了,使用 @就代表src目录
步骤二: 使用
components
节点注册组件步骤三 : 以标签形式,使用注册好的组件
在VSCode中配置@路径提示的插件
4-5 私有子组件和公有组件
通过components注册的是私有子组件例如:
- 在组件A 的components 节点下,注册了组件F
- 则组件F只能用在组件A中;不 能被用在组件C中
注册全局组件
- 在vue项目的
main.js
入口文件中,通过Vue.component()
方法 , 可以注册全局组件
- 在vue项目的
auto close tag
自动闭合标签的插件- ``
例子在vue2的demo-first中
4-6 为count组件声明props自定义属性
组件的props
props是组件的自定义属性,在封装通用组件时候,合理使用props可以极大提高组件的复用性
语法格式:
1
2
3
4
5
6
7
8export default {
//组件的自定义属性
props : ['自定义属性A', '自定义属性B', '...'],
//组件的私有数据
data(){
return { }
}
}
结合v-bind使用自定义属性
- init传来的是一个字符串,使用:
<Mycount :init="9"></Mycount>
- init传来的是一个字符串,使用:
- 组件的封装者
- 组件的使用者
props是只读的
init可以在模板中使用
组件中封装的自定义属性是只读的,程序员不能直接修改props的值。否则会报错:
props的default默认值
示例代码: props通过defult传递默认值
1
2
3
4
5
6
7
8export default {
props:{
init: {
// 用default 属性定义属性的默认值
default :0
}
}
}
props - required必填项
第五章 生命周期【我不会】+父向子传值+兄弟传值
5-1 样式冲突 – 了解scoped的使用和底层实现原理
问题:left.vue中的h3样式改动之后,影响到了right.vue的样式以及全局的h3样式
scope可以替代属性选择器,解不同组件间的的样式混用的问题
- !!!!和讲的不一样啊!!!!
当使用第三方组件库的时候,要修改第三方组件默认样式的需求,需要使用
/deep/
,例如: [vant](vant: 轻量、可靠的移动端 Vue 组件库 (gitee.com))
5-2 vue的实例对象
.vue结尾的文件,浏览器打不开,有一个编译的过程,.vue只是一个模板
- package.json中的
vue-template-compiler
会把每一行vue代码转换成页面可识别, 交给浏览器去执行
- package.json中的
5-3 生命周期和数据共享
vue不建议去手动获取dom元素,应该用ref
生命周期(Life Cycel) 是从一个组件从创建 –> 运行 —>销毁 的整个过程,强调的是一个时间段
生命周期函数 : 是由vue框架提供的内置函数,会伴随着组件的生命周期,自动按次序执行
组件生命周期函数的分类
组件创建阶段
组件运行阶段
组件销毁阶段
- 了解beforeCreate和created生命周期函数的特点
creates生命周期函数,很常用
经常在它里面,调用methods中的方法,请求服务器的数据
并且,把请求到的数据,转存到data中,供template模板渲染的时候使用
5-4 父乡子传值 – 使用自定义属性
项目开发过程中,组件之间最常见的关系分为:
- 父子关系
- 兄弟关系
父子组件之间的数据共享
- (1)父 –> 子 共享数据
- (2)子 –> 父 共享数据
父组件向子组件共享数据需要使用自定义属性(父组件传递数据给子组件)
示例代码 :
- 父组件
1
2
3
4
5
6
7
8
9//父组件
<Son :msg="message" :user = "userinfo"></Son>
data() {
return{
message : 'hello vue.js',
userinfo: {name: 'zs', age: 20}
}
}- 子组件
1
2
3
4
5
6
7
8<template>
<div>
<h5>父组件传递来的 msg值是</h5>
<p>父组件传递过来的 user 值是: {{ msg }}</p>
</div>
</template>
props: ['msg','user']
在子组件中修改父组件的对象值有两种情况,修改对象的值时重新指向新的对象;修改对象的某个属性值时全局的该对象值都改变了
1 | <button @click="msg = 'abc'">修改msg的值</button> |
- 不要修改props的值
5-5 子向父传值 – 自定义事件【你不会哦!!!这图可能都是错的】
子组件向父组件共享数据使用自定义事件,示例代码:
- 子组件
1
2
3
4
5
6
7
8
9
10
11
12export default{
data() {
return { count : 0}
},
methods: {
add(){
this.count += 1
//修改数据时, 通过 $emit() 触发自定义事件
this.$emit('numchange',this.count)
}
}
}父组件
1
2
3
4
5
6
7
8
9
10
11<Son @numchange="getNewCount "></son>
export default {
data() {
return { countFronSon : 0}
},
methods: {
getNewCount(val) {
this.countFronSon = val
}
}
}
5-6 兄弟组件之间的数据共享【演示EventBus的使用】
在vue2.x中,兄弟组件之间的数据共享的方案是EventBus
兄弟组件A(数据发送方)
1
2
3
4
5
6
7
8
9import bus from './eventBus.js'
export default {
data() {
return {
msg: 'hello vue.js'
}
},
}eventBus.js
1
2
3import Vue from 'vue'
//向外共享Vue的实例对象
export default new Vue()兄弟组件C (数据接收方)
1
2
3
4
5
6
7
8
9
10
11
12
13
14import bus from './eventBus.js'
export default {
data() {
return {
msgFromLeft: ''
}
},
created() {
bus.$on('share', val => {
this.msgFromLeft = val
})
}
}
- 创建eventBus.js模块,并向外共享一个Vue的实例对象
- 在数据发送方,调用**bus.$emit(‘事件名称’,要发送的数据)**方法触发自定义事件
- 在数据接收方,调用bus.$on(‘事件名称’,事件处理函数)方法注册一个自定义事件
第六章 ref控制DOM元素以及购物车案例【难到吐血】
6-1 使用ref应用DOM元素
vue优势: MVVM 在vue中,程序员不需要操作DOM。程序员只需要把数据维护好
- 在vue项目,墙裂不建议大家安装和使用Jquery!
- 在vue中,需要操作对象,需要拿到页面上的某个DOM元素的引用,方法:
ref引用:
- ref用来辅助开发者不依赖jQuery的情况下,获取DOM元素或组件的引用
- 每个vue的组件实例上,都包含一个$refs对象,里面存储着对应的DOM元素或组件。默认情况下,组件的$refs指向一个空对象
````js
<button @click = "showThis">打印 this</button>
export default {
methods:{showThis() { //当前APP 组件的实例对象 console.log(this); }
}
}//$开头的都是vue中的实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
4. ref的值不能相同
```js
<h1 ref="app">App 根组件</h1>
export default {
methods:{
showThis() {
//当前APP 组件的实例对象
// console.log(this.$refs.app);
this.$refs.app.style.color = "red";
}
}
}
```
5. **父组件直接调用子组件的方法**:
- 使用ref最简便,比父向子传值要简单的多
- 演示: 使用父组件的“重置”来使子组件的值变为0
```js
<button @click="onReset">重置Left组件的count</button>
<Left ref="comLeft"></Left>
import Left from '@/components/Left.vue'
export default {
methods:{
showThis() {
//当前APP 组件的实例对象
console.log(this.$refs.app);
this.$refs.app.style.color = "red";
},
//点击按钮,重置Left组件的count值
onReset() {
// this.$refs.comLeft.resetCount()
this.$refs.comLeft.count = 0
}
},
components:{
Left
}
}
```
##### 6-2 初步实现按钮和文本框的按需展示
1. ````js
<input type="text" v-if="inputVisible" @blur="showButton">
<button v-else @click = "showInput">展示输入框</button>
export default {
data(){
return {
//控制输入框和按钮的按需切换
inputVisible: false
}
},
methods:{
showInput() {
//点击按钮,展示输入框
//1. 切换布尔值,把文本框展示出来
this.inputVisible =true;
//2. 让展示出零四的文本框,自动获取焦点
//这里会报undefined,因为生命周期。页面渲染完毕之后才能执行
this.$nextTick(() => {
this.$refs.ipRef.focus()
})
},
showButton() {
this.inputVisible = false;
},
}
}ref- 了解
this.$nextTick
的应用场景- 组件的
$nextTick(cb)
方法,会把cb回调推迟到下一个DOM更新周期之后执行 - 即 等组件DOM更新完成之后,再执行cb回调函数,从而保证cb回调函数可以操作最新的DOM元素
- 组件的
6-3 购物车 案例【again,很重要啊!!!】
数组中的方法: some循环
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19<script>
const arr = ['小红', '你啦', 'DJ', 'dg'];
//forEach循环只要开始,会必须全部走完.return 都没有作用
// arr.forEach(item => {
// console.log('ok');
// if (item === '苏大强') {
// console.log(index);
// return;
// }
// })
arr.some((item, index) => {
console.log(index);
if (item === "DJ") {
console.log(index);
// 再找到对应的项之后,可以通过 return true固定的语法,来终止 some循环
return true;
}
})
</script>数组中的方法: every循环
- 只要任意一个state时不是true,旧返回false
- arr.filter(item => item.state).reduce((累加的结果, 当前循环项) => {}, 初始值)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18<script>
const arr = [{
id: 1,
name: '西瓜',
state: true
}, {
id: 2,
name: '黄瓜',
state: false
}, {
id: 3,
name: '西瓜',
state: true
}, ]
//需求:判断数组中,每个水果是否被选中
const result = arr.every(item => item.state === true)
console.log(result);
</script>数组的方法 : reduce的基本用法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46<script>
const arr = [{
id: 1,
name: '西瓜',
state: true,
price: 10,
count: 1
}, {
id: 2,
name: '西瓜',
state: true,
price: 10,
count: 1
}, {
id: 3,
name: '西瓜',
state: false,
price: 10,
count: 1
}, {
id: 4,
name: '西瓜',
state: true,
price: 10,
count: 1
}, ]
// 需求: 把购物车数组中,已勾选的水果,总价累加起来
/* let amt = 0 //总价
arr.filter(item => item.state).forEach(item => {
amt += item.price * item.count
})
console.log(amt); */
/*let amt = 0;
// arr.filter(item => item.state).reduce((累加的结果, 当前循环项) => {}, 初始值)
const result = arr.filter(item => item.state).reduce((amt, item) => {
return amt += item.price * item.count
}, 0)
console.log(result);*/
//最简写法:
const result = arr.filter(item => item.state).reduce((amt,item) => amt += item.price * item.count,0)
</script>
// 结果为30
6-4 购物车案例: 导入、注册、使用Header组件
组件化开发: 为了代码的复用
实现步骤:
- 初始化项目基本结构
- 封装MyHeader组件
- 基于axios请求商品列表数据(GET请求,地址为gttp://www.escook.cn/api/cart)
- 封装MyFooter组件
- 封装MyGoods组件
- 封装MyCounter组件
- 安装并在App中导入axios
- 在methods方法中,定义initCartList函数请求列表
- 在created生命周期函数中,调用步骤2封装的initCartList 函数
6-5 购物车案例– 为Goods组件封装title和pic属性
分别封装props两种方案的优缺点对比
子传父组件 : 自定义事件
在子组件中,要监听 复选框 状态变化的事件,拿到最新的勾选状态
<input type = "checkbox" @change = "stateChange">
只要复选框的勾选状态发生变化之后,会自动触发change事件
当监听到勾选状态变化之后,应该立即把最新的状态,通过 自定义事件的形式,发送给父组件
this.$emit('state-change',{id,value})
其中,id表示当前这件商品的id,value的值是最新的勾选状态
父传子组件: 自定义属性
第七章 动态组件 & 插槽 & 自定义指令
7-1
动态组件: 不同组件之间的按需展示: 不用v-if以及v-else
动态组件 值得是 动态切换组件的显示和隐藏
vue提供了一个
<component>
组件,专门用来实现动态组建的渲染介绍
component
标签的基础用法专门用来实现动态组件的渲染
is 属性指定哪个组件的名称,就显示哪个组件,is可以
<component :is= "comName"></component>
7-2 keep-alive
问题: Left组件中数字不断+1之后,切换回到Left组件之后值为0(default)
```js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
3. 使用keep-alive保持组件的状态: 哪怕被隐藏了,也不会被销毁,
- keep-alive可以把内部的组件进行缓存,而不是销毁
4. keep-alive 对应的声明周期函数
- 当组件被缓存时,会自动触发组件的**deactivated**声明周期函数
- 当组件**被激活**时,会自动触发组件的**activated**生命周期函数
##### 7-3 指定哪个组件可以被缓存
1. keep-alive 的 **include**属性
- include属性用来指定 : 只有**名称匹配的租价**会被缓存,多个组件名之间使用**英文的逗号**分隔
- 或者,通过exclude 属性指定哪些组件不需要被缓存,不要同时使用include和exclude两个属性
- ```js
<keep-alive include="Left,Right">
<components :is="comName"></components>
</keep-alive>name 属性
1
2
3
4
5
6
7
8
9<script>
export default {
// 当提供了name属性之后,组件的名称,就是name属性的值
// 对比
// 1. 组件的“注册名称” 主要应用场景是 : 以标签的形式,把注册号的组件,渲染和使用到页面结构之中
// 2, 组件声明时候的""name名称的只要应用场景: 结合<keep-alive>标签实现组件缓存功能;以及在调试工具中看到组建的name名称;在父组件中注册组件时不适用name值
name: 'MyLeft',
}
</script>
7-4 插槽【没有改了最后的案例】
插槽(Slot)是vue为组件的封装者提供的能力。允许开发者在封装组件时,把不确定的、希望由用户指定的部分定义为插槽
后备内容 : 封装组件的时候,可以为预留的
<slot>
插槽提供后备内容(默认内容)。如果组件的使用者没有为插槽提供任何内容,则后备内容会生效。示例代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20// App.vue中
<Left>
<!-- 默认情况下,在使用组件的时候,提供的内容都会被填充到名字为default 的插槽之中 -->
<!-- v-slot只能用于template标签上 -->
<!-- 1. 如果要把内容填充到指定名称的插槽中,需要使用v-slot: 这个指令
2. v-slot: 后面要跟上插槽的名字
3. v-slot:指令不能直接用在元素身上,必须用在template 标签上
4. tempalte 这个标签,它是一个虚拟的标签,只起到包裹性质的作用,但是,不会被渲染为任何实质性的html元素 -->
<!-- v-slot的简写 : # -->
<template #default>
<p>这是在Left 组件的内容区域, 声明的p标签</p>
</template>
</Left>
// Left组件中
<!-- 声明一个插槽区域 -->
<!-- vue官方规定: 每一个slot插槽,都要有一个name名称 -->
<!-- 如果省略了slot的name属性,则有一个默认名称叫做 default -->
<slot name="default">这是 default 插槽的默认内容</slot>具名插槽的定义和使用
- name不叫default的是具名插槽,是default的加匿名插槽
7-5 自定义指令
自定义指令 : vue官方提供了v-text, v-for, v-model, v-if 等常用的指令。初次之外vue还允许开发者自定义指令
vue中的自定义指令分为两类:
- 私有自定义指令
- 全局自定义指令
私有自定义指令:
在每个vue组件中,可以在
directives
节点下声明私有自定义指令1
2
3
4
5
6
7
8
9directives: {
color: {
// 为绑定到的HTMl元素设置红色的文字
bind(el){
// 形参中 的el时绑定了此指令的,原生的 DOM 对象
el.style.color = 'red'
}
}
}
私有自定义 — 案例 :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16<h1 v-color="color"> App根组件</h1>
<p v-color="'red'">测试</p>
directives: {
// 定义名为 color 的指令,指向一个配置对象
color: {
// 当指令第一次被绑定到元素上的时候,会立刻触发bind函数
// 形参中的el表示当前指令所绑定的那个DOM对象
bind(el, binding) {
console.log('触发了 v-color 的 bind');
// el.style.color ='red';
el.style.color = binding.value;
console.log(binding);
}
}
}
7-6 自定义指令 – update函数(函数简写形式)
- 如果bind 和 update函数中的逻辑完全相同,则对象格式的自定义指令简写成函数格式:
1 | directives: { |
1 | directives: { |
全局自定义指令需要通过”Vue.directive()”进行声明,示例代码:
1
2
3
4
5// 参数1: 字符串, 表示全局自定义指令的名字
// 参数2:对象,用来接收指令的参数值
Vue.directive('color', function(el, binding){
el.style.color = binding.value
})
第八章 eslint + axios + 路由
8-1 eslient没学明白
没有配置prettier
8-2 axios: 演示axios的基本用法并发现存在的问题
- get用法:
1 | <button @click="getInfo">发起get请求</button> |
post用法:
1
2
3
4
5
6
7
8
9
10
11
12
13<button @click="postInfo">发起 POST 请求</button>
<script>
import axios from 'axios'
export default {
methods: {
async postInfo(){
const { data: res} = await axios.post('http://www.liulongbin.top:3006/api/post',{name: 'zs',age: 20})
console.log(res);
}
}
}
</script>
8-3 把axios挂载到vue的原型上并配置请求根路径
main.js中【缺点: 无法实现API接口的复用,不利于接口的复用】
1
2
3
4
5
6
7
8
9
10import axios from 'axios'
// axios.defaults.baseURL = '请求根路径', 端口号之前都是请求的根路径
/* 全局配置axios的请求路径 */
axios.defaults.baseURL = 'http://www.liulongbin.top:3006'
//Vue原型上挂一个共享的成员,不需要每个文件import axios
/* 把axios 挂载到 Vue.prototype ,供每个.vue 组件使用*/
Vue.prototype.$http = axios
// 今后, 在每个.vue组件中要发起请求,直接调用 this.$http.xxx
8-4 路由
路由(route) : 就是对应关系
- 地址和组件的对应关系
SPA与前端路由
- 前端路由 : Hash地址 与 组件 之间的对应关系
- 前端路由底层的概念就是: 监听哈希地址的变换
实现前端路由
1
2
3
4
5
6
7
8
9export default {
name: 'App',
data() {
return {
// 要展示的组件的名称
comName: 'Name'
}
}
}
8-5 安装和配置路由
什么是vue-router
- vue-router是 vue.js 给出的路由解决方案,只能结合vue项目进行使用,能够轻松的管理SPA项目父母中组件的切换
vuerouter 的官方文档地址 : https://router.vuejs.org/zh/
- 安装 vue-router 包
- 命令
npm i vue-router@3.5.2 -S
- 命令
- 创建路由模块
- 导入并挂载路由模块
- 声明路由链接和占位符
- 安装 vue-router 包
创建路由模块
在src 源代码目录下,新建router/index.js路由模块,并初始化代码:
1
2
3
4
5
6
7
8
9
10
11
12//1. 导入Vue 和VueRouter 的包
import Vue from 'vue'
import VueRouter from 'vue-router'
//2. 调用Vue.use() 函数,把 VueRouter 安装为 Vue 的插件
Vue.use(VueRouter)
//3. 创建路由的实例对象
const router = new VueRouter()
//4. 向外共享路由的实例对象
export default routermain.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23import Vue from 'vue'
import App from './App.vue'
import axios from 'axios'
//导入路由模块,拿到路由的实例对象
import router from '@/router/index.js'
Vue.config.productionTip = false
// axios.defaults.baseURL = '请求根路径', 端口号之前都是请求的根路径
/* 全局配置axios的请求路径 */
axios.defaults.baseURL = 'http://www.liulongbin.top:3006'
//Vue原型上挂一个共享的成员,不需要每个文件import axios
/* 把axios 挂载到 Vue.prototype ,供每个.vue 组件使用*/
Vue.prototype.$http = axios
// 今后, 在每个.vue组件中要发起请求,直接调用 this.$http.xxx
new Vue({
render: h => h(App),
// 在Vue 项目中, 要想把路由用起来,必须把路由实例对象,通过下面的方式进行挂载
// router: 路由的实例对象
router
}).$mount('#app')src.router.index.js 就是当前项目的路由模块
8-6 在路由中声明路由的对应关系
前端路由的工作方式:
用户点击了页面上的路由链接
导致了URL 地址栏中的Hash值发生了变化
前端路由监听到了Hash地址的变化
前端路由把当前Hash地址对应的组件渲染到浏览器中
路由重定向:
- 指的是: 用户在访问地址A的时候,强制用户跳转到地址C,从而展示特定的组件页面。
- 通过路由规则的redirect属性,指定一个新的路由地址,可以很方便地设置路由重定向
8-7 嵌套路由
通过路由实现组件的嵌套展示:
- 模板内容中又有自己路由链接
- 点击子级路由链接显示子级模板内容
通过children 属性声明 子路由规则
默认子路由
Right.vue中
1
2
3
4<router-link to="/right/">tab1</router-link>
<router-link to="/right/tab2">tab2</router-link>
<hr>
<router-view></router-view>index.js中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16routes: [
{ path: '/home', component: Home },
{ path: '/left', component: Left },
{
path: '/right',
component: Right,
//路由的重定向,重指定地址跳到另一个新地址
// redirect: '/about/tab1',
children: [
//子路由规则
// 默认子路由:如果 children 数组中,某个路由规则的path值为空字符串,则这个 路由规则,叫做"默认子路由"
{ path: '', component: Tab1 },
{ path: 'tab2', component: Tab2 },
]
}
]
8-8 动态路由 – 基本用法
之前的路由规则的复用性差
动态路由匹配 : 把Hash地址中可变的部分定义为参考项,从而提高路由规则的复用性
在vue-router中把英文的冒号(:)来定义路由的参数项,示例代码:
1
2
3
4
5
6//路由中的动态参数以 : 进行声明,冒号后面的是动态参数的名称
{path: '/movie/:id',component:Movie}
//将一下3个路由规则,合并成一个,提高了路由规则的复用性
{path: '/movie/1',component: Movie}
{path: '/movie/2',component: Movie}
{path: '/movie/3',component: Movie}
动态路由—- 为路由规则开启props传参
- app2.vue中
1
2
3
4<router-link to="/left/3">左边</router-link>
<router-link to="/left/1">左边</router-link>
<router-link to="/left/2">左边</router-link>
<router-view></router-view>Left中
1
2
3
4
5
6
7
8
9
10
11
12
13
14<h3>Left组件 -- {{ $route.params.mid }} -- {{ mid }}</h3>
<script>
export default {
name:'Left',
props: ['mid'],
methods: {
async getInfo() {
const {data: res} = await this.$http.get('api/get')
console.log(res);
}
}
}
</script>index.js中
1
{ path: '/left/:mid', component: Left, props: true },
动态路由—- 为路由规则开启props传参
- 先给index.js 路由规则添加props
- 再
8-9 拓展query和fullPath
- 注意: 再hash 地址中, /后面的参数项,叫做“路径参数”
- 在路由“参数对象”中,需要使用this.$route.params 来访问路径参数
- 注意2: 在hash地址中, ?后面的参数项,叫做“查询参数”
- 在路由参数对象中,需要使用 this.$route.query 来访问查询参数
- 注意3. 在this.$route 中,path 只是路径部分,full Path是完整的地址
第九章 导航+ 案例(由taken哦!!)
9-1 编程式导航跳转 – push,replace,go
- 声明式导航
- 在浏览器中,点击链接实现导航的方式,叫做声明式导航
- 例如:
- 普通网页中点击链接,vue项目中点击
都属于声明式导航
- 普通网页中点击链接,vue项目中点击
- 编程式导航
- 在浏览器中,调用API方法 实现导航的方式,叫做编程式导航
- 例如: 普通网页中调用location.href 跳转到新页面的方式,属编程式导航
- vue-router中的编程式导航 API
this.$router.push('hash地址')
- 跳转到指定 的hash地址,并增加一条历史记录
this.$router.replace('hash地址')
- 跳转到指定的hash地址,并替换掉当前的历史记录
this.$router.go(数值n)
- 调用
this.router.go()
方法,可以在浏览器中前进和后退。示例代码:
- 调用
- $router.go的简化方法:
- 实际开发中,一般只用前进和后退一层页面。因此vue-router 提供了两种便携方法
$router.back()
: 后退到上一个页面$router.forward()
: 前进到下一个页面
- 实际开发中,一般只用前进和后退一层页面。因此vue-router 提供了两种便携方法
9-2 导航守卫
导航守卫 : 可以控制路由的访问权限
全局前置守卫
每次发生路由的导航跳转时,都会触发全局前置守卫,在全局前置守卫中,程序员可以对每个路由进行访问权限的控制
1
2
3
4
5
6// 创建路由实例对象
const router = new VueRouter({...})
//调用路由实例对象的 beforeEach 方法,即可声明“全局前置守卫”
// 每次发生路由导航跳转时候,都会自动触发 fn 这个“回调函数”
router.beforeEach(fn)全局前置守卫 的回调函数中接收3个形参,格式:
1
2
3
4
5
6
7
8
9//创建路由实例对象
const router =new VueRouter({})
// 全局前置守卫
router.beforeEach((to,from,next) =>{
// to时将要访问的路由的信息对象
// from 是将要离开的路由的信息对象
// next是一个函数,调用next() 表示函数,调用 next() 表示放行,允许这次路由导航
})
next的三种调用方式
- 参考示意图,分析next函数的3中调用方式最终结果:
导航守卫— 控制访问权限
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22router.beforeEach(function(to, from, next) {
//next函数表示放行的意思
next()
//1. 拿到用户访问的hash地址
// 2. 判断hash地址是否等于 /main
//2.1 如果等于 /main,证明需要登陆之后,才能访问成功
//2.2 如果不等于/main,则不需要登录,直接放行next()
//3. 如果访问的地址是/main, 则需要读取localStorage中的token值
// 3.1 如果由token,则放行
//3.2 如果没有 token,则强制跳转到/login 登录页
if (to.path === '/mian') {
//要访问后台主页,需要判断是否有token
const token = localStorage.getItem('token')
if (token) {
next()
} else {
//没有登录,强制跳转
next('/login')
}
}
})