# Vue_workspace
**Repository Path**: li-kewei123/vue_workspace
## Basic Information
- **Project Name**: Vue_workspace
- **Description**: 关于Vue的代码
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2023-02-21
- **Last Updated**: 2023-05-02
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
目标计划:
```
coderwhy老师全套课程链接:https://pan.baidu.com/s/1enC95F9XoSY5bWlFhulv9Q?pwd=q5m5 提取码:q5m5
最新接口地址:baseURL = "http://123.207.32.32:7888/api/hy66"
看一下我下面两个接口的使用方法,建议先在浏览器测试,学会接口的使用,再去修改自己的代码。
```

# 前置知识
```html
Vue:
和之前操作DOM的方式完全不一样,思想都不一样,编程范式(模式)也不一样。
从零学习Vue开发。
需要具备一定的HTML、CSS、JavaScript基础。
ES6语法
promise。new promise(写异步,有专门处理成功的回调,好处理失败的回调) 。
axios
以后我们基本上是写ES6的语法,很少写ES5的语法,通过Babel工具来让ES6语法转成ES5让浏览器支持。
给浏览器使用的还是ES5的语法,项目中开发过程中都是ES6语法。ES6肯定比ES5更好用。
ES6语法规范:结构赋值、模板字符串、箭头函数等
ES6模块化:默认暴露、分别暴露、统一暴露、恩enpate\ispote等--可能会拼错
包管理器:npm、yarn、cnpm等会一个就行
原型和原型链(原理):重点
数组的常用方法:过滤一个数组、加工一个数组、筛选最值等
Typescript:
比起ES6更好用。
jQuery:
过去的20多年,大家都在使用jQuery,可能一些老项目里面会有jQuery。
慢慢正在退出历史的舞台。
Github仓库里面,jQuery组织宣布在慢慢移除jQuery代码,已经不在使用jQuery。
慢慢退出,现在jQuery处于慢慢向三大框架的过渡阶段。
因为有些公司还在使用jQuery,所以现在我们都要学习jQuery和三大框架。
当我们引入vue.js之后,会把vue注册成为一个全局变量,类似于jQuery对象。
原来引入jQuery的时候,全局多了$和jQuery两个关键词。
但是不学前置知识,也可直接上手Vue,只是理解不是那么深刻。学习Vue也会讲一些命令给其串下去。
```
# 目标
合计232集每日10集
第一集还没看,是综合类的,后面继续看。
```
1.Vue基础
2.vue-cli Vue脚手架,专门做工程化开发的。
3.vue-router,用于在Vue中实现前端路由的。
4、vuex,应用足够复杂时,借助vuex保管数据
```
# 一、关于Vue.js

## 1、Vue.js的重要性
```
原来:
前端和后端都能写页面。
很多东西都要使用命令行工具来干,前端开发原来不受重视,不需要掌握命令行工具。7-8k薪资。
自从Chrome V8引擎出来后,各种服务器端框架(例如Node.JS)就出来了,前端就流行了。12k薪资。
自从有了node,后端Java能干的事,前端都能干。例如:
Java可以搭建一个服务,tomacat可以搭建一个web服务。
node.js也能搭建一个web服务。
后端工程师:后端接口
例如:controller、Service、Dao等接口封装好等待前端请求。
但是Java主要是往分布式方向发展的,分布式会发展的越来越好。
前端工程师:15-16年前端就开始比较流行啦
直接访问controller就行,通过路径访问请求,发送请求,得到想要的数据即可。
数据在页面中渲染前端工程师来管。
前端体系:后端可以做的前端都可以做。
用途:
目前市场上比较流行的前后端分离的开发模式,大多前端都是vueJS做的,具体的优点请大家看官方文档。
10家公司7-8家基本都是Vue。
如果你现在正在换工作,你会发现招聘前端的需求中,10个有8个都对Vue有或多或少的要求。
```




## 2、老项目特点
```
原来可能使用的原生开发或者jQuery开发,重构Vue老项目。
一个完整的项目里面,既有jQuery代码,也有Vue.js代码。
一点一点的引入,把Vue.js作为应用的一部分嵌套进去,带来更加丰富的交互体验。
渐进式:可以从一点一点的进行重构,直至重构的界面越来越多。
Vue.js的交互体验确实是比jQuery的交互体验更好。
问题:如果对项目进行全方面的重构的话,任务量是非常大的。
解决方法:可以分页面进行重构。
其中一个页面:继续使用jQuery,不对其进行重构。
另外一个界面:引入Vue.js框架,慢慢去除界面里面的JQuery代码,直至全部去除。
```
## 3、新项目特点
```
新项目:新项目决定使用Vue的技术栈
如果你希望将更多的业务逻辑使用Vue实现,那么Vue的核心库以及其生态系统。
Vue全家桶包括:基础语法(Vue核心Core)、组件、Vue路由(Vue-router)、Vuex等。
全家桶可以满足更大项目、更复杂业务逻辑都可以使用全家桶来开发,也可以满足你各种各样的需求。
启发:
以后出来的w.js需要自学的时候,来重构原来项目,也需要学习原来的老项目。
可以把Vue.js作为项目的一部分,也可以全部使用Vue.js框架进行开发。
总结:
不断学习,但是很多技术是相通的。
大部分公司不会给自己时间去学习框架,多数公司都是满足进度要求,抓紧时间做。一般学习框架,一边做项目。
大部分公司是不会给自己时间来学习的,项目来了直接上手去做。
```
## 4、Vue和Angular的区别?
```
三大框架中,目前比较重要的是Vue,比其他两个还重要。
Vue.js在国内使用的很多,面试也问的很多。
在Vue里面,Vue和Vue.js是没有区别的。Angular1.x版本叫Angular,后面的版本叫Angular。
公司开发中,很少公司使用Angular,多数使用Vue,即便使用Angular.js,也是使用最新版本。
相比其它的 MVVM 框架(例如angular.js也是MVVM框架),Vue.js 更容易上手。
后起之秀:Vue之前有React,React之前有Angular。Vue框架参考了React和Angular。
Angular:
学习Angular框架的时候,还需要学习jQuery。
Angular和Angular.js的区别?
Angular:新的版本,不在使用ES6,直接使用TypeScript。1.x以后的版本叫Angular。
在国内,使用Angular的新版本是比较多的。
Angular.js:原来学习还在使用ES5。1.x版本叫Angular.js。
在国内,Angular.js在公司里面使用的比较少。
原来学习的是Angular.js,一般学习完Angular.js还要学习一下Angular。
在Vue中,Vue和Vue.js是没有区别的。
```
## 5、Vue和jQuery的区别?
```
编程范式和编程模式完全不一样。
```
## 6、Vue的官网
英文官网:https://vuejs.org/ 网址后缀为`org`的一般是开源的
中文官网3.0:https://cn.vuejs.org/
中文官网2.0:https://v2.cn.vuejs.org/
```html
Vue官网:已经把Vue3作为默认版本,原来是Vue2作为默认版本,使用时需要切换Vue版本。
现在目前企业或者市场主流开发依然使用的Vue2,但是Vue3绝对是未来发展的趋势。
Vue2过渡到Vue3的阶段。Vue2在4年间迭代更新70多次(从2.0.0-2.6.74)。
目前要求:Vue2(是经典版本,即将淘汰但也要会)+Vue3(趋势)
Vue CLI2和Vue CLI3虽然都有了,但是一些老的项目在使用Vue CLI2,一些新的项目在使用Vue CLI3了。
前面讲解的时候,可以使用Vue CLI2的知识讲解,后面在做项目的时候,可以使用Vue CLI3来进行项目。
```

## 7、Vue的读音
```
Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。
不要读错,以后面试的时候也不要读错。
例如:读x三个音,读叉一个音。读叉code。读起来更简单。
iPhone x 读 iPhone 叉
xcode是一款IOS开发的IDE。
```
## 8、Vue的作者
```
一位华裔前 Google 工程师,尤雨溪是Vue.js框架的作者,HTML5版Clear的打造人,独立开源开发者。
他认为,未来App的趋势是轻量化和细化,能解决问题的应用就是好应用。而在移动互联网时代大的背景下,个人开发者的机遇在门槛低,成本低,跨设备和多平台四个方面。
尤雨溪毕业于上海复旦附中,在美国完成大学学业,本科毕业于Colgate University,后在Parsons设计学院获得Design & Technology艺术硕士学位,后任职于纽约Google Creative Labs(谷歌创意实验室),曾经任职Meteor Development Group(Meteor开发小组)。
由于工作中大量接触开源的JavaScript项目,最后自己也走上了开源之路,现全职开发和维护Vue.js。
2014年2月,开发了一个前端开发库Vue.js。Vue.js 是构建 Web 界面的JavaScript库,是一个通过简洁的API提供高效的数据绑定和灵活的组件系统。
2016年9月3日,在南京的JSConf上,Vue作者尤雨溪正式宣布加盟阿里巴巴Weex团队,尤雨溪称他将以技术顾问的身份加入 Weex 团队来做 Vue 和 Weex 的JavaScript runtime整合,目标是让大家能用 Vue 的语法跨三端(桌面应用/Web 应用/手机 App)。
尤玉溪大学专业并非是计算机专业,在大学期间他学习专业是室内艺术和艺术史,后来读了美术设计和技术的硕士,正是在读硕士期间,他偶然接触到JavaScript,从此被这门编程语言深深吸引,开启了自己的前端生涯。
他的Github上面,他不仅仅是做了Vue,还做了其他。尤玉溪的作品不仅仅有Vue,还有其他。
更多看:百度百科。
2016年开始应该是互联网飞速发展的几年,同时也是Web前端开发非常火爆的一年,Web 前端技术发展速度让人感觉几乎不是继承式的迭代,而是一次次的变革和创造。
这一年中有很多热门的前端开发框架,下面为大家总结2016年至今最受欢迎的几款前端框架。
2016年前端特别火爆,Java比前端更难学,2016年angular.js相当火爆,但是自从前端三大框架出来后,angular.js的热度就降了一些。
```


```
Taylor otwell是Python领域的大牛。他的粉丝基本都是学习编程的,明星代言,就火起来了。
Vue的图标颜色是绿色,代表着勃勃生机。
他不想自己一个人或者公司使用这一个小框架,于是对外发布。其实刚发布那时,没人会关注一个小框架,Taylor是PHP里面一个知名框架作者,一直都很有名气,粉丝比较多。
后起之秀:Vue之前有React,React之前有Angular。Vue框架参考了React和Angular。
Angular三大框架里面最早流行的,2015年左右很火,后面React火了,尤玉溪觉得Angular太笨重了。
Vue2.0版本发布后,慢慢就火起来了。大型公司会使用Anguar和React。出去面试10家里面有8.5家都是Vue。
Vue2在4年间更新了70多次版本,从2.0.0-2.7.x,现在处于Vue2到Vue3的过渡阶段,Vue3是未来的趋势。
Vue早期只关注于视图层核心库,慢慢的加功能,例如Vue路由、状态管理、Vue脚手架爱等,慢慢的发展成为一个渐进式框架。
```
## 8、理解Vue的渐进式框架
```
特点:从简单到复杂。
一点一点的来,可以把Vue当成一个核心库来使用,只用核心功能。
阶梯式向前,渐进式就是指我们可以由浅入深、由简单到复杂的方式去使用vue.js.
渐进式意味着你可以将Vue作为你应用的一部分嵌入其中,带来更丰富的交互体验。
把Vue的整个前端生态拿过来使用,重构/构建前端页面。
一个界面可能既有原生代码、jQuery代码、Vue代码。
例如:公司要引入一批设备,先从某个部门引入试用,慢慢推广到全部替换。
使用Vue构建新项目:
如果你希望将更多的业务逻辑使用Vue实现,那么Vue的核心库以及其生态系统。
使用Vue的全家桶:Core+Vue-router+Vuex,也可以满足你各种各样的需求。
Vue核心+Vue路由+Vue状态管理
可以满足大项目、复杂业务逻辑的开发。
可以进入一些基于Vue插件进行开发。
```
## 9、理解构建用户界面
```
Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。
简言之:构建用户界面,就是把得到的数据通过Vue里面的一套东西(插值表达式、指令等)转换为用户可以看到的界面。
至于数据是来自后台服务器还是数据mock,请求方式是异步还是同步,都不在Vue的职责范围之内。
面试题:谈谈对于构建用户界面的理解?
前端开发的工作职责是:在合适的时候发送对应的请求,获取对应的数据,以界面的形式展示给用户看。
写微信小程序步骤:(1)写静态页面 (2)对接后台数据
答:把得到的数据转换成用户可以看到的界面。模板结合数据形成一个界面。MVVM构成了用户界面。
```

## 10、学习Vue的工具介绍
```
postman工具:前端写一个东西查看效果是否好。可以直接发送请求查看是否给到了数据,只要结果传通了,其他交给前端了。也可以发权限、身份认证、权限拦截等都可以测出来。
```
## 11、Vue的特点
数据和界面进行解耦、虚拟DOM、组件化。
(1)采用组件化模式,提高代码复用率、且让代码更好维护。组件之间分别封装起来,互不影响。
一个.vue文件就是一个组件。

(2)声明式编码,让编码人员无需直接操作DOM,提高开发效率。
操作案例:

方法一:JS操作(命令式编码)
```
让你往前走一步,老师发一句命令,你往前走一步,不发出命令你就不走了,说一下动一下。
下图少了任何一步都不行,少了任何一步都不行
```

方法二:Vue操作(声明式编码)
口渴直接喝水。
```html
-
{{p.id}} - {{p.name}} - {{p.age}}
```
(3)使用虚拟DOM+优秀的`Diff`算法,尽量复用DOM节点。

```
如果数据发生变化,上面的就不好使用了。
下图是把原来有的覆盖掉了,不方便,也会影响效率。本可以直接添加差异化的东西,这样显的很方便。
如果数据量比较大,用原生JavaScript写的效率就非常低下啦。
```

```
如果改用Vue去实现,比较方便,中间多了一个环节叫做虚拟DOM。
可以把虚拟DOM理解为内存里面的一个数据。
如果数据不变化,一直是死数据,张三、李四、王五,虚拟DOM对我们没有帮助。
但是数据有变化,虚拟DOM就有作用。
Diff算法会进行比较。
```

```
Vue里面的高级功能是jQuery不具备的,这些高级功能后面会解释到。
解耦视图和数据:一会写代码可以理解。
可复用的组件:学到组件化开发可以理解。开发一个组件,可以在多个界面使用。
前端路由技术:Vue-router会讲到。
状态管理:什么是一个状态管理?有哪些状态需要管理?
虚拟DOM:Vue的底层实现。
这些特点,不需要一个个去记住,我们在后面的学习和开发中都会慢慢体会到的,一些技术点我也会在后面进行讲解。
```
## 12、Vue.js 是什么
Vue (读音 /vjuː/,类似于 **view**) 是一套用于构建用户界面的**渐进式框架**。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与[现代化的工具链](https://v2.cn.vuejs.org/v2/guide/single-file-components.html)以及各种[支持类库](https://github.com/vuejs/awesome-vue#libraries--plugins)结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
如果你想在深入学习 Vue 之前对它有更多了解,我们[制作了一个视频](https://v2.cn.vuejs.org/v2/guide/#),带您了解其核心概念和一个示例工程。
如果你已经是有经验的前端开发者,想知道 Vue 与其它库/框架有哪些区别,请查看[对比其它框架](https://v2.cn.vuejs.org/v2/guide/comparison.html)。
```
初步解释:与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。
深层次解释:Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。
```

Vue核心功能:是一个视图模板引擎,但这不是说Vue就不能成为一个框架。
如下图所示,这里包含了Vue的所有部件,在声明式渲染(视图模板引擎)的基础上,我们可以通过添加组件系统、客户端路由、大规模状态管理来构建一个完整的框架。更重要的是,这些功能相互独立,你可以在核心功能的基础上任意选用其他的部件,不一定要全部整合在一起。可以看到,**所说的“渐进式”,其实就是Vue的使用方式,同时也体现了Vue的设计的理念。**

```
Vue的库:由核心库和一系列相关的插件组成
Vue核心库:比较轻量,可以实现一些基础的功能,可只使用核心功能,如果需要一些其他的功能,我们可以在核心库的基础上添加进来其他的插件。
另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
Vue.js是以数据驱动和组件化的思想构建的。
```
## 13、Vue.js安裝
```
框架使用步骤:使用任何一个第三方框架,第一步都需要下载,安装,引用等。
```
方式一:直接CDN引入
适用于把项目发布出去,CDN引入代码下载效率更高,CDN会选择更近的服务器,把jQuery或者Vue代码下载下来。
```JavaScript
使用到数据代理proxy
(2)vm身上所有的属性及Vue原型上所有的属性,在 Vue模板中都可以直接使用。
```
### 14.3 计数器的MVVM
```
我们的计数器中就有严格的MVVM(Model View ViewModel)思想
View依然是我们的DOM
Model就是我们我们抽离出来的obj
ViewModel就是我们创建的Vue对象实例
它们之间如何工作呢?
首先ViewModel通过Data Binding让obj中的数据实时的在DOM中显示。
其次ViewModel通过DOM Listener来监听DOM事件,并通过methods中的操作,来改变obj中的数据。
有了Vue帮助我们完成VueModel层的任务,在后续的开发,我们就可以专注于数据的处理,以及DOM的编写工作了。
```

### 14.4 抽离data
```html
测试一下1:{{$options}}
测试一下2:{{$emit}}
测试一下3:{{_c}}
```
总结:
所有的属性都绑定到了vm身上,vm实际上就是Vue实例对象。
只要是绑定到vm身上的属性,在模板中都能显示出来。
### 14.5 拓展

```
其实这种开发方式,就是我们常说的MV*模式
MVC、MVVM、 MVP等都是MV*的衍生物
搞清楚了这种代码组织结构的目的,就会明白这些模式本质上都是一回事。
让数据与视图间不会发生直接联系。
其实说到这里,你应该知道“DOM流存在缺陷的原因,在“DOM流”中其实是把dom当做Model,我们直接从dom中获取数据,随后又改变dom来更新视图,视图和模型其实是混在一起了,代码组织自然很混乱,不易维护。
而这种MV*的代码组织方式,渐渐的就演变成了所谓的框架。
团队开发中会选择使用框架的一个重要的原因,因为框架提前设定好的代码的组织结构让实际开发项目的代码有一个相对明确地方,这样不用担心因为团队中某个人疏忽或特有编码习惯, 造成代码整体的混乱。
这里说句题外话,依照现在对框架的认识,严格来说Bootstrap并不是一个框架,其实只是一个CSS工具集,主要用来做界面美化。
Jquery也并不涉及代码的结构组织,只是把一些重复的操作进行简化 (如 DOM操作 Ajax操作等),再加上对于兼容性的解决,所以只是用来方便操作的JS库。
现在利用`MV*`的代码组织方式,我们拥有了可以应对需求变化的健壮代码。
在使用过程中,开发人员逐渐发现在应对有频繁数据更新的需求时,我们总在做着同样的工作—获取DOM,依照新的数据来更新视图。
这些工作繁琐且重复,实质上耗费了开发人员的精力。
为了解决这个问题,基于MV*的模式的MVVM框架诞生—Knockout。
它利用实例的形式,把model层内容传入到实例所谓的view model中,利用binding方法完成view model与view之间的双向绑定,view mode中数据变化时,view发生变化,反之亦然。
这段对于Knockout描述可能有点抽象, 毕竟上没有上代码,但你至少知道Knockout框架能替我们完成了从数据更新后视图相应的更新就行了,如下图所示。
```

```
你可能会感叹,具有这么先进理念和功能的框架,自己怎么没用过,甚至之前没有听说过。
这是因为Knockout诞生的时候超越了它的时代,还记得这段开头提到MVVM框架产生的原因吗—应对有频繁数据更新的需求,而在当时前端页面的大部分就只涉及静态展示和简单交互,不存在频繁的数据变更,使用Jquery 足矣。
就这样,Knockout在当时并没有流行起来,不过这个框架现在依然存在,感兴趣的可以去看看,上手也很简单 。
直到最近几年,随着随着关于数据频繁变动的需求越来越多,人们又开始重视这种自动更新视图的理念了。
Vue就是继承这种理念的众多框架之一。如下图所示,在具有响应式系统的Vue实例中,DOM状态只是数据状态的一个映射 即 UI=VM(State) ,当等式右边State改变了,页面展示部分UI就会发生相应改变。很多人初次上手Vue时,觉得很好用,原因就是这个。不过需要注意的是,Vue的核心定位并不是一个框架,设计上也没有完全遵循MVVM模式,可以看到在图中只有State和View两部分, Vue的核心功能强调的是状态到界面的映射,对于代码的结构组织并不重视, 所以单纯只使用其核心功能时,它并不是一个框架,而更像一个视图模板引擎,这也是为什么Vue开发者把其命名成读音类似于view的原因。
```

```
框架:某些程序员把一些基础功能封装好,包含了特定的功能和特定的界面,自己在使用时,不用纠结底层实现,按照特定规范等直接拿来使用即可。
```
## 15、方法和函数的区别
方法:methods 方法和实例对象是挂钩的
函数:function
开发中不区分函数和方法
js里面:既有方法,也有函数
Java里面:只有方法,直接没有函数的概念
```JavaScript
```
## 16、Vue的生命周期
```
Vue的生命周期里面做了很多复杂的操作。
生命周期:事务从诞生到消亡的整个过程。
Vue也有自己的生命周期,也会做很多事情,一般是不会销毁的,因为Vue里面有一个循环,我们也有办法让Vue销毁。
人也是有生命周期的,会做一系列的事情。例如:吃饭、上学、找工作、结婚生子...
```

图示生命周期:
```
官方提供的生命周期函数:
绿色部分:Vue内部在做的事情。
红色部分:在Vue实例中我们可以实现的函数。
组件生命周期函数也是类似的,不过组件生命周期函数是会销毁的。
```
```html
```


## 17、Vue源码
Vue的源码:https://github.com/vuejs/vue
下载源码注意事项:
```
下载源码的时候不要直接进去就download,我们要先选择分支,再下载。
Branch dev 开发中版本,我们在公司开发,不会使用正在开发中的版本。
我们使用的一定是一个稳定的版本。
release 测试、释放:该版本是很稳定的。
公司里面版本分为:debug版本(开发阶段)、release版本(发布时候) debug/release
一个稳定的版本开发完成之后,我们会打一个tag标签,tag的版本是真正发布的版本。
```

```
文件/src目录/core目录/index.js---->入口文件
index.html-----整个网页html的入口
index.js-----整个网页js的入口
```
```JavaScript
//index.js代码
import Vue from './instance/index' //导入Vue
// 省略不必要代码
export default Vue//ES6的导出Vue new Vue实际上new的就是new导出的这个Vue
```
```JavaScript
// 文件/src目录/core目录/instanse/render-helpers/index.js部分代码
// 原来定义一个对象
function Person(options参数) { }
// 执行函数并传递对象
new Person({})
// 现在定义一个对象,就是我们new Vue的东西
//同理
function Vue(options) {
// 判断是生产环境还是开发环境
if (__DEV__ && !(this instanceof Vue)) {
warn('Vue is a constructor and should be called with the `new` keyword')
}
// 初始化,并把options传进去
this._init(options)//_init()是一个函数
}
```
```javascript
// instanse/render-helpers/init.js部分代码
export function initMixin(Vue: typeof Component) {
// 在Vue的原型上放了一个init
Vue.prototype._init = function (options?: Record) {
const vm: Component = this
// a uid
vm._uid = uid++
// 继续调用其他的init函数,做其他的一些操作
// 初始化操作,例如初始化状态
initLifecycle(vm)
initEvents(vm)
initRender(vm)
//callHook 通过这个来回调,看生命周期
//beforeCreate还没有完全创建出来之前
callHook(vm, 'beforeCreate', undefined, false /* setContext */)//做完上面3行代码,给这个回调
initInjections(vm) // resolve injections before data/props
// 初始化状态
initState(vm)
initProvide(vm) // resolve provide after data/props
//callHook 通过这个来回调,看生命周期
callHook(vm, 'created')//做完上面3行代码,给这个回调
// hook钩子有回调的意思,生命周期函数也叫钩子函数
// 传过来的函数,我通过钩子来回调你
}
}
```
# 二、体验Vue.js
## 1、体验Vue.js的响应式
(1)Vue的源码里面肯定是定义了一个Vue的函数:
```javascript
function Vue(){}
//同理
//传递普通类型的参数进去
function Person(name,age){}
```
(2)后面我们就可以直接写构造函数:通过new关键字创建Vue实例的时候,传入一个对象
```JavaScript
//参数是一个对象
new Vue({})
new Person({})
// 普通类型的参数。
let vm = new Person('张三', 18)
// 对象类型的参数。
const x = new Vue({})
//当年引入jQuery全局也是多了两个人,一个是$,一个是jQuery关键词
//引入Vue,全局多了一个内置对象or构造函数Vue
//全局多出来Vue对象或者构造函数:函数两个身份->函数和对象
```
(3)可以使用一个变量来接收:
```JavaScript
// 在ES6中,一般不使用var,使用let和const
var app = new Vue({})
// let定义变量
let app = new Vue({})
// const定义常量,以后不需要改动app,所以设置为常量
const app = new Vue({})
```
(4)let和`const`的区别:
注意:var是有很多的缺陷的,没有变量的作用域的概念,使用的时候非常不好用,是JavaScript设计早期的一个缺陷。
在`ES6`中改变了,使用let和`const`。
```JavaScript
let name = '张三'
name = '李四'
const age = 18
age = 19//报错
var height = 1.88
height = 2.01
```
(5)原理分析
通过Vue管理,去解析div里面的语法。
特殊语法,例如插值表达式里面有一个变量,回来data里面找数据,进行解析。
```html
Vue实例不会来管理:{{age}}
Vue实例会来管理:{{msg}}
数组转换为字符串直接展示:{{movies}}
- {{movies[0]}}
- {{movies[1]}}
- {{movies[2]}}
{{item}}
```
如果服务器返回的数据发生改变,界面不用更改,会根据新的数据在div里面展示新的数据。

后面给数组追加元素的时候, 新的元素也可以在界面中渲染出来。

```
和jQuery比较:
上面案例展示中只是更改另外数据,没有往ul里面添加代码。
如果是jQuery来操作,需要再创建一个li,往li里面再添加最后一条数据。
现在展示:
只需要告诉Vue数据怎么展示,声明出来就行。
自动创建li,并自动放在指定的位置上。
界面会自动添加。
我们越来越不愿意写jQuery代码了。
再也不需要在JavaScript代码中完成DOM的拼接相关操作。
而且,更重要的是,它还是响应式的。
也就是说,当我们数组中的数据发生改变时,界面会自动改变。
依然让我们打开开发者模式的console,来试一下
```

(6)原生js或jQuery的做法:编程范式是命令式编程
```javascript
//命令式编程:一步一步的告诉你怎么做,命令式的告诉你
1.创建一个div元素,设置id属性
2.定义一个变量message
3.将message变量放在前面的div元素中显示
4.修改message的数据:今天天气不错
5.将修改后的数据再次替换到div元素中
```
(7)总结
```
当数据发生改变的时候,界面会自动发生一些响应,界面会自动发生改变。
体验vue响应式:数据发生改变时,界面会自动发生改变。
代码做了什么事情?
我们来阅读JavaScript代码,会发现创建了一个Vue对象。
创建对象的时候,可以传入一些参数,这里传入的参数是对象类型的参数。对象里面又包含其他一些属性。
创建Vue对象的时候,传入了一些options:{}
{}中包含了el属性:该属性决定了这个Vue对象挂载到哪一个元素上,我们这里是挂载到了id为app的元素上。
{}中包含了data属性:该属性中通常会存储一些数据。
这些数据可以是我们直接定义出来的,比如像上面这样。
这些数据也可能是来自网络,从服务器加载或者请求过来的,再把数据放到data里面。
浏览器执行代码的流程:
执行到10~13行代码显然出对应的HTML
执行第16行代码创建Vue实例,并且对原HTML进行解析和修改。
```
注意:代码是从上往下解析的,当解析到插值表达式的依旧是插值表达式,一旦解析到变量,就把变量拿上去。
## 2、模板语法
计算属性
事件监听
条件判断
循环遍历
阶段案例
v-model
### 2.1 插值操作
```
总结:Vue模板语法有两大类
(1)插值语法:
功能:用于解析标签体内容,放置在标签体中。
写法:{{xxx}},xxx是js表达式,且可以直接读取到data中所有的属性。
(2)指令语法:
功能:用于解析标签(包括:标签属性、标签体内容、给标签绑定事件. . . . . .)
举例:v-bind:href="xxx" 或 简写为 :href="xxx" ,xxx同样要写js表达式,
且可以直接读取到data中的所有属性。
```
#### 2.1.1 Mustache
Mustache: 胡子,胡须
```html
Hello,{{message}}!
{{firstName + lastName}}
{{18+2}}
{{firstName + ' ' + lastName}}
{{firstName}} {{lastName}}
{{getFullName()}}
{{fullName}}
{{fullName1}}
{{counter * 2}}
>
```
案例演示:

#### 2.1.2 v-once
```
once 一次
但是,在某些情况下,我们可能不希望界面随意的跟随改变
这个时候,我们就可以使用一个Vue的指令
该指令后面不需要跟任何表达式(比如之前的v-for后面是由跟表达式的)
该指令表示元素和组件(组件后面才会学习)只渲染一次,不会随着数据的改变而改变。
```
```html
```
效果展示:

#### 2.1.3 v-html
```
某些情况下,我们从服务器请求到的数据本身就是一个HTML代码
如果我们直接通过{{}}来输出,会将HTML代码也一起输出。
但是我们可能希望的是按照HTML格式进行解析,并且显示对应的内容。
如果我们希望解析出HTML展示
可以使用v-html指令
该指令后面往往会跟上一个string类型
会将string的html解析出来并且进行渲染
```
```html
```
演示效果:

#### 2.1.4 v-text
v-text作用和Mustache比较相似:都是用于将数据显示在界面中
v-text通常情况下,接受一个string类型
```html
Hello,{{message}}!
Hello,!
```
#### 2.1.5 v-pre
```
v-pre用于跳过这个元素和它子元素的编译过程,用于显示原本的Mustache语法。
比如下面的代码:
第一个h2元素中的内容会被编译解析出来对应的内容
第二个h2元素中会直接显示{{message}}
```
```html
{{message}}
{{message}}
百度的标签和链接是:百度一下
```
效果展示:

#### 2.1.6 v-cloak
```
在某些情况下,我们浏览器可能会直接显然出未编译的Mustache标签。
该指令在学习Angular的时候学过。
cloak: 斗篷 clock:时钟
以后我们也不会使用v-cloak指令,以后写的模板都会渲染成一些函数,我们以后真正使用的是虚拟DOM。
```
当用户在运用到`{{message}}`的时候,js里面的代码报错了,就不能获取到该变量,显示的是`{{message}}`。给用户感觉肯定是不友好的,用户看不懂`{{message}}`是什么意思。
解决办法:还在执行到`{{message}}`代码的时候,让其隐藏起来,当运行到js代码的时候,在显示出来。
例如:在Vue解析之前,div中有一个属性v-cloak
```html
{{message}}
演示效果:1秒钟后才会显示出来Vue.js
```
改进方法:在Vue解析之后,div中没有一个属性v-cloak
```html
```
第21步:修改默认的class值(单独改)
```vue
首页
关于
```
修改默认的class值(整体改)
```js
const router = new VueRouter({
routes,
mode:'history',
linkActiveClass:'x'
})
```
第22步:通过代码跳转路由
push方法:可以返回
```vue
```
repalce方法:不可以返回
```vue
```
第23步:动态路由
实现效果:
```
http://localhost:8080/user/zhangsan
http://localhost:8080/user/lisi
```
在index.js中配置:
```js
const routes = [
{
// path: '/user',//原始
// path: '/user/:user_id/',//都行
path: '/user/:userId/',//驼峰原则
component: User
}
]
```
App.vue:
```vue
首页
关于
用户
```
效果展示:像这样配置是找不到组件的,点击用户会出现空白现象。

修改:App.vue
```vue
用户
```
```vue
首页
关于
用户
用户
用户
{{ userInfo }}
{{ $route.params.abc }}
{{ msg }}
{{ finalMsg }}
```
第24步:使用路由懒加载到router/index.js中
方式一:推荐---->方便管理
```js
// import Home from '../components/Home.vue'
// import About from '../components/About'
// import User from '../components/User.vue'
const Home = () => import('../components/Home.vue')
const About = () => import('../components/About')
const User = () => import('../components/User')
```
方式二:不推荐
```js
const routes = [
{
path: '/user/:abc/',
component: () => import('../components/User')
}
]
```
第25步:组件中的路由嵌套
(1)创建子组件
```vue
```
```vue
```
(2)配置嵌套路由
```js
// router/index.js
const HomeNews = () => import('../components/HomeNews')
const routes = [
{
path: '/home',
component: Home,
children:[
{
path:'',
redirect:'message'
},
{
path:'news',//以后会自动拼接成/home/news的
component:HomeNews
},
{
path:'message',
component:() => import('../components/HomeMessage')
}
]
}
]
```
(3)在首页中显示路由出口
```vue
```
第25步:参数传递
```
URL = scheme://localhost:80/path?query#fragment
scheme:http协议、ftp协议、tcp协议。
post:请求的网页默认是80端口,80端口浏览器是可以省略的
path:服务器放资源的路径
fragment:片段,做GPU开发就有片段
https:www.bai.com:80 80即使端口
http://localhost:8080/profile?name=likewei&age=18
http://localhost:8080/profile/userId/?name=likewei&age=18
/profile/userId/是path
userId是params
```
```vue
档案
档案
档案
{{ $route.query }}
```
```VUE
我是档案组件
{{ $route.query.name }}
{{ $route.query.age }}
```
第26步:动态标题解决办法
方式一:麻烦
```vue
```
```VUE
```
方式二:全局导航守卫
```js
//router/index.js
router.beforeEach() 点击beforeEach跳转
// router.d.ts
beforeEach(guard: NavigationGuard): () => void 按住Ctrl点击NavigationGuard
// type相当于typedefine,给NavigationGuard起别名(内容)
// extends 继承
// 是一个泛型------TS语言里面的
export type NavigationGuard = (
//参数1
to: Route,
//参数2
from: Route,
//参数3
next: NavigationGuardNext
) => any //箭头函数执行的代码
afterEach(hook: (
//参数1
to: Route,
//参数2
from: Route
//参数3:因为跳转完了,到最后就不需要跳转了
) => any): () => void
```
```js
//router/index.js
const routes = [{
path: '/home',
component: Home,
meta: {
title: '首页页面'
}
},
{
path: '/about',
component: About,
meta: {
title: '关于页面'
},
beforeEnter: (to, from, next) => {
console.log('进入了');
next()
}
}
]
const router = new VueRouter({
routes,
mode: 'history',
linkActiveClass: 'x'
})
// 前置钩子(hook),前置守卫(guard)----组件还没渲染出来就把标题改了
// router.beforeEach(function(to,from,next)){}
// 简写
router.beforeEach((to, from, next) => {
// 从from跳转到to
// 一级组件展示
// document.title = to.meta.title
next() //必须要写,覆盖内部写好的,才能执行跳转下一步,不写就不动了
// 实战:如果用户登录,可以进入该页面
console.log(to);
// 二级组件展示 matched[0]拥有取第一个
document.title = to.matched[0].meta.title
})
// 后置钩子(hook)----在跳转后进行的回调
router.afterEach((to, from) => {
console.log(from + '后执行');
})
```
## 5、vue-router源码解析
```
在package.json中看到的版本不一定是当前使用的版本。具体可以到node_modules/vue-router里面查找。
看源码的时候,最好先从package.json中开始看,从哪里指向。
```
router/index.js
```
开发中执行Vue.use(VueRouter)时,就会执行VueRouter.install
```
src\index.js 入口
```js
// 定义VueRouter
export default class VueRouter {
static install: () => void;
}
VueRouter.install = install // 按住Ctrl点击install跳转到install.js
```
install.js
```js
// 传入Vue类
export function install (Vue){
_Vue = Vue
// 翻译
Vue.prototype.$router = return this._routerRoot.router;
// 源码
Object.defineProperty(Vue.prototype, '$router', {
get () { return this._routerRoot._router }
})
// 翻译
Vue.prototype.$route = return this._routerRoot.route;
// 源码
Object.defineProperty(Vue.prototype, '$route', {
get () { return t his._routerRoot._route }
})
// 注册全局组件,全局都可以使用
// 组件写法通常是HomeMsg写成
Vue.component('RouterView', View)
Vue.component('RouterLink', Link)
}
```
所有组件都继承着Vue的原型:
```js
// src/main.js
Vue.prototype.test = function(){
//Vue和所有组件都多出来一个test方法
console.log('test');
}
Vue.prototype.$router= '哈哈哈哈' ;//涉及到内部执行顺序问题,因为内部有一个,我们自己在这里又定义一个
Vue.prototype.$color= 'red' ;
```
```
任何一个组件中可以调用
this.test()
this.name
```
往对象里面添加属性:
```js
// 方式一
const obj = {
name: '张三'
}
// 方式二:定义属性
Object.defineProperty(obj,'age',18)
```
## 6、插槽
```
插槽的使用:讲了两个
第一个是插槽的基本使用。
第二个是具名插槽:
掌握了具名插槽之后我们就可以封装很多的独立组件了
而且我们封装的组件适应性也很强,可以在很多的地方使用该独立组件。
```
一般的插槽:
```
在生活中很多地方都有插槽,电脑的USB插槽,插板当中的电源插槽。
插槽的目的是让我们原来的设备具备更多的扩展性。
比如电脑的USB我们可以插入U盘、硬盘、手机、音响、键盘、鼠标等等。
```
组件的插槽:
```
定义组件的时候也是可以定义插槽的。
组件的插槽也是为了让我们封装的组件更加具有扩展性。
让使用者可以决定组件内部的一些内容到底展示什么。
一般在自定义可复用组件的时候,会用到插槽。
```
第01步:插槽的基本使用
```html
```
第02步:实现要求
```
让组件具有扩展性
```

封装原理:

```
例如:移动网站中的导航栏。
移动开发中,几乎每个页面都有导航栏。
导航栏我们必然会封装成一个插件,比如nav-bar组件。
一旦有了这个组件,我们就可以在多个页面中复用了。
但是,每个页面的导航是一样的吗?No,我以京东M站为例
```

第03步:实现代码
```
如何去封装这类的组件呢?
它们也很多区别,但是也有很多共性。
如果,我们每一个单独去封装一个组件,显然不合适:比如每个页面都返回,这部分内容我们就要重复去封装。
但是,如果我们封装成一个,好像也不合理:有些左侧是菜单,有些是返回,有些中间是搜索,有些是文字,等等。
如何封装合适呢?抽取共性,保留不同。
最好的封装方式就是将共性抽取到组件中,将不同暴露为插槽。
一旦我们预留了插槽,就可以让使用者根据自己的需求,决定插槽中插入什么内容。
是搜索框,还是文字,还是菜单。由调用者自己来决定。
有些一样,有些不一样。一样的东西封装到组件里面,不一样的东西预留为插槽。
这就是为什么我们要学习组件中的插槽slot的原因。
```
第03步:直接写一个slot是没用的
浏览器是不会渲染出来的。
```html
```
第04步:替换代码
```html
哈哈哈
呵呵呵呵
```
第05步:给slot默认值
```
如果没有传递就会显示插槽里面默认的值。
如果有指定就会显示外面的内容。
```
```html
按钮
```
第06步:全部替换
```html
1
2
3
```
第07步:总结
```
了解了为什么用slot,我们再来谈谈如何使用slot?
在子组件中,使用特殊的元素就可以为子组件开启一个插槽。
该插槽插入什么内容取决于父组件如何使用。
我们通过一个简单的例子,来给子组件定义一个插槽:
中的内容表示,如果没有在该组件中插入任何其他内容,就默认显示该内容
有了这个插槽后,父组件如何使用呢?
```

相关代码:
```html
傻蛋
老总
Vue
好家伙
niubi
```
第08步:具名插槽的使用
```html
左边
中间
右边
```
第09步:替换元素,结果三个都改为标题了。
```html
标题
左边
中间
右边
```
需求:我们只需要其中的某一个,不要改其他的。
第10步:给插槽起名字
```html
标题
左边
中间
右边
没有名字将被替换
```
```html
标题1
标题2
左边
中间
右边
没有名字将被替换
```
第11步:总结
```
掌握了具名插槽,就可以去封装很多独立组件,封装的组件适用应很强。
当子组件的功能复杂时,子组件的插槽可能并非是一个。
比如我们封装一个导航栏的子组件,可能就需要三个插槽,分别代表左边、中间、右边。
那么,外面在给插槽插入内容时,如何区分插入的是哪一个呢?
这个时候,我们就需要给插槽起一个名字
如何使用具名插槽呢?
非常简单,只要给slot元素一个name属性即可
我们来给出一个案例:
这里我们先不对导航组件做非常复杂的封装,先了解具名插槽的用法。
```

相关代码1:
```html
```
相关代码2:具名插槽
```html
来来来
左边
中间
右边
```
第12步:编译作用域
```html
```
```
在真正学习插槽之前,我们需要先理解一个概念:编译作用域。
官方对于编译的作用域解析比较简单,我们自己来通过一个例子来理解这个概念:
我们来考虑下面的代码是否最终是可以渲染出来的:
中,我们使用了isShow属性。
isShow属性包含在组件中,也包含在Vue实例中。
答案:最终可以渲染出来,也就是使用的是Vue实例的属性。
为什么呢?
官方给出了一条准则:
父组件模板的所有东西都会在父级作用域内编译;使用的变量都是使用父级的变量。
子组件模板的所有东西都会在子级作用域内编译。使用的变量都是使用子级的变量。
而我们在使用的时候,整个组件的使用过程是相当于在父组件中出现的。
那么他的作用域就是父组件,使用的属性也是属于父组件的属性。
因此,isShow使用的是Vue实例中的属性,而不是子组件的属性。
```

第13步:作用域插槽
```html
```
不像那样展示:
```vue
javascript-
C++-
python-
```
解决方法:从子组件里面获取到,在父组件里进行展示
```vue
{{item}}
```
让子组件传递过去给父组件:
```vue
{{item}} -
{{slot.data.join('%%')}}
```
join函数使用:
```js
const vm = new Vue({
components: {
cpn: {
template: '#cpn',
data() {
return {
pLanguage: ['java', 'python', 'javascript', 'c++', 'c#', 'go', 'swift']
}
},
created() {
// join() 数组转换为字符串,多个元素以-进行连接
this.pLanguage.join('&&')
}
}
}
})
```
总结:作用域插槽
```
作用域插槽是slot一个比较难理解的点,而且官方文档说的又有点不清晰。
这里,我们用一句话对其做一个总结,然后我们在后续的案例中来体会:
父组件替换插槽的标签,但是内容由子组件来提供。
我们先提一个需求:
子组件中包括一组数据,比如:pLanguages: ['JavaScript', 'Python', 'Swift', 'Go', 'C++']
需要在多个界面进行展示:
某些界面是以水平方向一一展示的,
某些界面是以列表形式展示的,
某些界面直接展示一个数组
内容在子组件,希望父组件告诉我们如何展示,怎么办呢?
利用slot作用域插槽就可以了
我们来看看子组件的定义:
```

```
在父组件使用我们的子组件时,从子组件中拿到数据:
我们通过获取到slotProps属性
在通过slotProps.data就可以获取到刚才我们传入的data了
```

## 7、网络模块的封装
```
1、在项目中,使用到网络请求时,需要对其进行封装。
2、现在封装好,以后可以直接在项目中进行使用。
3、在前端开发过程中,需要发送对应的网络请求,去服务器请求数据。把数据请求过来,前端界面对数据进行进一步展示,这个时候必然需要使用到网络请求。
4、Vue中发送网络请求/模块有很多种选择,如下
第三方框架:需要对第三方框架进行封装。
建议:以后开发不是面向第三方框架来进行网络请求的,而是使用自己封装好的模块进行网络请求。
原因:
第三方框架可能在某一天不维护,或者出现严重的bug、严重的漏洞等,是一件非常危险的事情。
如果在整个应用程序中,有很多地方对第三方框架有依赖的话,这时如果想要切换框架,是非常麻烦的事情。
总结:不建议直接使用第三方框架。
学习主要内容:
常见的网络请求模块,以及优缺点对比。
JSONP的原理和封装----JSONP已经讲解过很多遍了。
JSONP原理回顾
JSONP请求封装
axios的内容详解
认识axios网络模块
发送基本请求
axios创建实例
axios拦截器的使用
```
第01步:网络请求选择如何选择?
```
选择一(不用,or很少直接使用):基于传统的Ajax,即基于`XMLHttpRequest(XHR)`进行封装。
缺点:
封装好后, 配置过程和调用方式/过程等非常混乱。
自己封装/编码的话,封装过程也比较头疼。
封装成功后并不一定是非常完善的,可能会出现各种各样的Bug。
学习中:可能会自己封装一下,看内部是怎么样的一个运行机制。
一般在真实的线上环境里面,是很少来封装这个东西的。
选择二(替代品):jQuery-Ajax
缺点:
在Vue、React、Angular整个开发/项目中都是不需要使用jQuery了。 jQuery的代码1w+行。Vue的代码才1w+行。
在Angular.js中还在使用jQuery,现在的Vue、React、Angular都不在使用jQuery都不使用了。
为了进行一个网络请求/功能, 特意引入一个jQuery/整个jQuery框架是不合理的----得不偿失
选择三:Vue1.x时,官方使用Vue-resource插件, Vue-resource的体积相对于jQuery小很多。
缺点:
在Vue2.0退出后, 2016年11月3日,Vue作者就在GitHub的Issues中说明了去掉vue-resource, 再也不会更新/维护vue-resource。
随着项目更新/Vue的更新,vue-resource就会出现各种各样的问题。
不在支持新的Vue版本。
对以后的项目开发和维护都存在很大的隐患。
一般情况下,如果一个框架不在维护了,项目一般都会慢慢替换掉。
例如:2050年,Vue公司宣布不在更新Vue了,我们的项目就会慢慢替换掉Vue框架,使用ChatGPT等流行框架。
选择四:axios库
在说明不再继续更新和维护vue-resource的同时,
作者还推荐了一个框架: axios框架----->axios有非常多的优点, 并且用起来也非常方便。
功能特点:
(1)在浏览器中发送 XMLHttpRequests 请求
(2)支持在node.js中发送 http请求
jQuery-Ajax是不能在node环境里面使用的,jQuery是不能在node环境中发送http请求。
(3)支持 Promise API
(4)支持拦截请求和响应
每发送一次网络请求,都是可以进行拦截的。
在发送网络请求的过程中,想做一些额外的操作,可以对请求进行拦截的。
拿到响应结果后,对响应结果进行一些转化,也是支持对响应结果进行一些拦截的。
(5)转换请求和响应数据:与拦截有关
. . . . . .
补充:
axios没有具体的翻译,不是一个具体的单词: ajax i/o system. i/o输入输出
通过这个框架,可以在网络中进行一些输入输出一些的操作。
```
第02步:jsonp
```
在前端开发中, 我们一种常见的网络请求方式就是JSONP
使用JSONP原因:解决跨域访问的问题。
JSONP的原理是什么呢?
JSONP的核心在于通过
```
总结:
```
IOS开发的时候,使用框架ASI---->后面改用AFN
ASI不在维护了,框架出现问题,很多地方都要换成AFN,只能一个个的改,很危险。
```
第23步:对网络请求的代码进行封装
```js
新建src/network目录/request.js
// 向服务器发送网络请求
// 方式一:只导出一个网络请求
// export default instance0(){}
// 方式二:封装多个实例的请求
export function instance1(){
}
export function instance2(){
}
```
实际开发:
```js
// request.js
import axios from 'axios'
export function request(config) {
// 1、创建axios的实例
const instance = axios.create({
baseURL: 'http://123.207.32.32:8000',
timeout: 5000
})
// 发送真正的网络请求
instance(config)
// 处理结果,但是不合适在这里处理结果,要把这个结果给调用者传递出去
.then(res => {
console.log(res);
})
// 异常也要回调出去
.catch(err => {
console.log(err);
})
}
```
问题:怎么传递出去请求
方法一:让别人传递`config`进来的时候,传递`success`
```js
// request.js
// 传递进来一个success成功函数,failure失败函数
export function request(config, success, failure) {
const instance = axios.create({
baseURL: 'http://123.207.32.32:8000',
timeout: 5000
})
instance(config)
.then(res => {
success(res) //回调出去
})
.catch(err => {
failure(err) //回调出去
})
}
```
别人使用方法:封装一个request模块
```js
// main.js
// 导入request函数
import {
request
} from './network/request';
request({
url: '/home/multidata'
}, res => {
console.log(res);
}, err => {
console.log(err);
})
```
方法二:request中只传递一个参数
```js
// request.js
import axios from 'axios'
export function request(config) {
const instance = axios.create({
baseURL: 'http://123.207.32.32:8000',
timeout: 5000
})
instance(config.baseConfig)
.then(res => {
config.success(res)//config.success实际上是取出来function(res){}
})
.catch(err => {
config.failure(err)
})
}
```
别人来使用的时候:
```js
// main.js
request({
baseConfig: {
},
success: function (res) {
},
failure: function (err) {
}
})
```
方法三:最终方案
```js
// request.js
import axios from 'axios'
export function request(config) {
return new Promise((resolve, reject) => {
const instance = axios.create({
baseURL: 'http://123.207.32.32:8000',
timeout: 5000
})
instance(config)
.then(res => {
resolve(res)
})
.catch(err => {
reject(err)
})
})
}
```
别人来使用的时候:
```js
// main.js
import { request } from './network/request';
request({
url: '/home/multidata'
}).then(res => {
// 正确结果
console.log(res);
}).catch(err => {
// 错误结果
console.log(err);
})
```
方法四:最最终方案
```js
// request.js
import axios from 'axios'
export function request(config) {
const instance = axios.create({
baseURL: 'http://123.207.32.32:8000',
timeout: 5000
})
return instance(config)
// instance本身返回的就是Promise,所以删除掉原来的Promise
}
```
第23步:如果有一天,不用axios框架了,改用android框架
```js
// request.js
import andriod from 'android'
export function request(config) {
andriod代码
// 把 andriod代码包装到Promise中即可
return new Promise()
}
```
第24步:总结
```js
function test(aaa, bbb) {
aaa('Hello,World') //调用function(){},即aaa = function(res){}
bbb('err message') // bbb = function(){}
}
test(function (res) {
console.log(res);
}, function () {
console.log(err);
})
```
第25步:如果发送网络请求时,
```
如果在使用axios发送网络请求之前,想要对某些请求进行一个拦截。
拼接一些东西
查看是否携带一些东西
一旦发生网络请求,在页面上增加某个动画等等
把请求的整个过程给拦截下来,使用axios的拦截器。
axios的拦截器包括:
请求成功的拦截
请求失败的拦截
响应成功时候的拦截
响应失败时候的拦截:服务器没有给具体的数据过来,给了一个错误码
Ts不是一个简单的脚本了,跟Java很像,里面有很多的脚本。
TS里面有:类型、泛型、可选类型,用?表示
```
第26步:请求拦截
```js
// main.js
request({
url: '/home/multidata'
}).then(res => {
// 正确结果
console.log(res);
}).catch(err => {
// 错误结果
console.log(err);
})
```
```js
//request.js
import axios from 'axios'
export function request(config) {
// 1、创建axios的实例
const instance = axios.create({
baseURL: 'http://123.207.32.32:8000',
timeout: 5000
})
// 2、axios的拦截器
// axios.interceptors()//全局拦截
// 拦截实例-拦截请求
instance.interceptors.request.use(config => {
console.log(config); //这行和上行的参数可以把config改为aaa,参数名字可自己命名
return config; //拦截后要返回出去,拦下来还回去才能请求成功
// 1、比如config中的一些信息不符合服务器的要求。例如,要对数据进行改变再发送到服务器
// 2、比如每次发送网络请求时,都希望在界面中显示一个请求的图标。例如:发送时有个转圈图标,得到数据消失
// 3、某些网络请求(比如:token),必须携带一些特殊信息。没有携带token就让其登录去。
}, err => {
console.log(err); //没发送请求出去,发送失败,一般都能发送出去的,来到这里很少
});
// 3、发送真正的网络请求
return instance(config)
}
```
第27步:响应拦截
```js
//main.js
request({
url: '/home/multidata'
}).then(res => {
// 处理结果
console.log(res)
}).catch(err => {
})
```
```js
// request.js
import axios from 'axios'
export function request(config) {
// 1、创建axios的实例
const instance = axios.create({
baseURL: 'http://123.207.32.32:8000',
timeout: 5000
})
instance.interceptors.request.use(config => {
return config;
}, err => {
});
instance.interceptors.response.use(res => {
// console.log(res);
return res.data;
}, err => {
//baseURL: 'http://123.207.32.32:8000/aaaa'改为这个就会打印
console.log(err); //打印其中一个
});
return instance(config)
}
```
# 四、Vuex
第01步:
在线文档:https://v3.vuex.vuejs.org/zh/
Github地址:https://github.com/vuejs/vuex
> 标准叫法:Vuex,国际化(标准的)会念x
>
> 不标准读音:Vuex\xcode\iphonex\xml 国内一般念叉,为了交流方便。
第02步:概念
```
vuex,当应用比较复杂时候,可以借助它帮助我们保管数据。
官方解释:Vuex 是一个专为 Vue.js 应用程序开发的状态管理的模式/工具。
Vuex集中式存储管理,应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
Vuex也集成到 Vue 的官方调试工具 devtools extension,提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级调试功能。
专门在 Vue 中实现集中式状态(数据)管理的一个 Vue 插件,对 vue 应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信。
如果做过React开发或者其他开发,可以清除意识到Vuex就是状态管理工具。
状态管理模式、集中式存储管理这些名词听起来就非常高大上,让人捉摸不透。
使用概念来解释概念,就会听不懂,Vue的官方文档,在国内已经算是写的非常好的。
```
第03步:解释概念
```
解释1:
集中式:
有20个同学都想学习,就可以召集起来在一个教室里面。
我在讲台上讲课,只讲一次,听课的有20个同学,有20种思维和20多种理解。
分布式:孙悟空拿20根头发,变成20个老师,去20个同学家里讲课,讲了20遍。
解释2:
状态(数据):
例如案例TodoList里面保存着一堆要做的事情起名为todos,这一堆要做的事就是数据或者状态或者状态数据。
解释3:因为是插件,使用vuex:Vue.use(Vuex)
```
第04步:状态管理到底是什么?
```
解释:
例如10个甚至更多个组件,里面的状态是希望共享的,很多组件都能共用。
于是,可以把这个状态(变量里面可以保存程序的状态,使用变量来存储状态)。
变量存储在任何一个组件里面都不合适,因为如果状态存储在一个单纯的组件里面,另外一个组件想要使用,就会相想尽各种办法获取到状态,可能里面的组件向外面的组件获取状态,从而形成一个组件树,传递数据的时候就需要一层一层的传输,但这样是不方便的,很复杂。
```
第05步:图例解释概念

第06步:解决方法
```
● 多个组件之间需要共享状态
○ 如果放到一个组件里面,获取该状态需要有很多组件的层级关系,取起来不方便。
○ 多个组件里面都有一个变量想要共享,放哪个组件都不合适。
○ 其实,你可以简单的将其看成把需要多个组件共享的变量全部存储在一个对象(new一个对象)里面。
■ 这个对象帮助我们管理状态。
○ 然后,将这个对象放在顶层的Vue实例中,让其他组件可以使用,所有的变量都可以共享了。
○ 那么,多个组件是不是就可以共享这个对象中的所有变量属性了呢?
```

第07步:实现方式(伪代码):不用Vuex
```js
// 组件1、组件2、Vue实例是相对独立的,又有一些状态想要共享,可以搞一个公共对象
// 可以把状态放到公共对象里面,一起来使用这个状态
const shareObj = {
name:'中国',
//name:'美国'//不是响应式的数据。没有加入到响应式系统里面。
}
// 所有的组件都继承着Vue的原型-----即下面2个组件以及所有组件都有name属性了
Vue.prototype.shareObj = shareObj
// 注册组件1
Vue.component('cpn1',{
this.shareObj.name//获取到name
})
// 注册组件2
Vue.component('cpn2',{
})
// Vue实例
const app = new Vue({
el:'#app'.
data:{}//这里的数据等所有东西都被加入到Vue的响应式系统里面了,所以这里的数据可以共享、响应式
})
缺点:中国不是响应式的,之前学习的Vue里面有一套响应式系统,为了实现响应式,专门开发了一款插件Vuex
```
```
等等,如果是这样的话,为什么官方还要专门出一个插件Vuex呢?难道我们不能自己封装一个对象来管理吗?
当然可以,只是我们要先想想VueJS带给我们最大的便利是什么呢?没错,就是响应式。
如果你自己封装实现一个对象能不能保证它里面所有的属性做到响应式呢?
当然也可以,只是自己封装可能稍微麻烦一些。
自己也能封装响应式,但是再往深层次封装,如果封装的非常好,就是Vuex.
我们就在重复的造轮子(没有必要),已经有了还在封装,工作两三年自己也能封装。
Vuex是参考React、Redis进行封装的。
不管是Vue,还是React,都是比较注重状态管理的东西。
不用怀疑,Vuex就是为了提供这样一个在多个组件间共享状态的插件,用它就可以了。
```
第07步:有什么状态时需要我们在多个组件间共享的呢?
```
● Vuex里面一般都是放一些需要在多个界面共享的状态。
○ 不是什么东西都可以往里面塞的。有些放到Vuex里面,有些放到组件里面进行管理。
○ 乱七八糟的放,不方便我们进行维护,变的非常臃肿。
● 多个组件都需要共享,并且组件之间层级关系比较多的。
父子组件之间的状态就没有必要放进去了。
直接父组件通过组件之间的通信,直接传给子组件即可,没必要塞到Vuex中。
```
第08步: 如果你做过大型开放,你一定遇到过多个状态,在多个界面间的共享问题。
```
比如用户的登录状态、用户名称、头像、地理位置信息等等。
用户的登录状态:
很多界面都用到登录状态。很多界面在去服务器启动数据的时候,都需要携带一个token令牌。
去服务器请求数据不是随便请求的。
有些数据是针对某些登录的用户才能请求的,发送请求的参数里面必须携带token。
没有token是请求不到这个数据的。
多个界面请求数据的时候都需要用到这个token。
需要把用户登录成功之后,服务器返回的token保存到Vuex里面。
当多个界面都需要用到token的时候,就可以从Vuex拿到token使用。
用户的地理位置:
美团、百度外卖都需要获取用户当前的位置。
位置信息也在多个界面进行共享,就可以放到Vuex里面。
电商应用的收藏:
多个界面都需要收藏。商品的收藏
很多界面都有收藏按钮的。
如果每个界面都搞一个数组来作为收藏的商品是不合适的。
每次点击这个收藏按钮,就将这个收藏的这个商品直接放到Vuex里面。
在Vuex里面搞一个数组,直接做一个收藏即可。
购物车中的物品:
这个界面可以加购,另一个界面也可加购,专门有一个界面是展示所有加入购物车的商品的。
加入购物车里面的所有商品放到Vuex里面进行管理。
总结:
这些状态信息,我们都可以放在统一的地方,对它进行保存和管理,而且它们还是响应式的。
从理论上理解了状态管理之后,让我们从实际的代码再来看看状态管理。
```
第09步: 要在单个组件中进行状态管理是一件非常简单的事情

```
图片作用:Vue解释单页/界面面的状态管理,图中包含如下三个角色
State:
变量一般是用来保存状态的,变量一般是保持到data(){return{message:'Vue.js'}}
相当于data:{里面的变量,存储当前界面/组件中的多个状态}。
你姑且可以当做就是data中的属性,里面的状态指向模板,指向界面,在模板中进行展示
View:
视图层,可以针对State的变化,显示不同的信息。
View中可以产生一些行为Action,例如:界面中用户发生了点击事件
Actions:
这里的Actions主要是用户的各种操作:点击、输入等等,会导致状态的改变。
```
代码展示:App.vue 只在一个界面中进行数据的变换
```vue
{{ message }}
```
第10步:与组件之间共享状态, 多个界面中进行数据的变换 。
方式一:通过父子组件之间的传递(父子传值)
```vue
```
```vue
{{ counter }}
```
第11步 方式二:通过Vuex来管理
```shell
原始的package.json中是没有vuex的,我们需要安装
{
"dependencies": {
"vue": "^2.5.2",
"vue-router": "^3.0.1",
"vuex": "^3.0.1"//只有安装之后才有
}
}
npm i vuex@3.0.1 --save` # 安装Vuex插件 --save即以后项目上线\运营\部署后依旧要使用
```
第12步:main.js中可以写
```js
// 引入\导入Vuex包
import Vuex from './vuex'
// 使用Vuex,进行实例化。创建实例来管理状态
Vue.use(Vuex)
//缺点:但是不建议这么写,因为会导致混乱和代码越来越多,main.js代码越来越大/多
```
第13步:重放
```js
//src/store(vuex也行)/index.js
import Vue from 'vue'//需要使用到Vue
import Vuex from 'vuex'
//1、安装插件,底层会去执行插件的install方法。Vue-router也是一样的事情
Vue.use(Vuex)
//底层做的事情
// Vuex.install = 底层源码
// 2、创建对象
// 之前是创建VueRouter对象并传递一些参数
// new VueRouter({})//原来
// 区别:真正使用的是Vuex插件里面的Store
// new一个类,里面可以传递一些参数
const store = new Vuex.Store({ })
// 每一个store里面存储着一些特别的信息
// 但是Vue只是推荐一个store,方便以后进行维护
const store1 = new Vuex.Store({})
// 3、导出store对象,我们让所有的Vue组件都可以使用这个store对象
export default store
```
第14步:挂载到App.vue中
```js
import router from './router'
// 挂载store对象,导入store对象,并且放在new Vue中
import store from './store'
new Vue({
el: '#app',
router,
store, //挂在到这里来
components: {
App
},
template: ''
})
// 才会给Vue的原型属性中添加这样一个操作/属性
// Vue.prototype.$store = store // 以后在其他组件中才可以通过$store获取/使用store相关的东西
```
第15步:store/index.js中存放的东西一般是固定的
```js
const store = new Vuex.Store({
// State:state是一个对象,保存共享状态的地方
state: {
// 键值对
},
// Mutation:通过mutation来修改状态。Vuex的store状态的更新唯一方式:提交Mutation
mutations: {
//方法\函数
},
// Action:做一些异步操作,放到mutations里面修改状态
actions: {
},
// Getters:类似于组件里面的计算属性
// 当一个data:{message:'Vue.js'}直接展示就行了
// 当数据需要一系列变化时候再使用,使用计算属性
getters: {
// state里面数据需要经过某种变化在展示
// 方法/函数
},
// Module:划分一些模块,针对不同的模块进行相关数据的保存
modules: {
}
})
```
第16步:State的对象
定义状态:
```js
// store/index.js
const store = new Vuex.Store({
state: {
name: '张三'//在其他多个界面就可以共享此状态了
}
})
```
使用状态:
```vue
{{ $store.state.counter }}
```
```vue
App.vue中的内容{{ $store.state.counter }}
```
第17步:总结
```
单界面状态管理的实现
在这个案例中,我们有木有状态需要管理呢?没错,就是个数counter。
counter需要某种方式被记录下来,也就是我们的State。
counter目前的值需要被显示在界面中,也就是我们的View部分。
界面发生某些操作时(我们这里是用户的点击,也可以是用户的input),需要去更新状态,也就是我们的Actions
这不就是上面的流程图了吗?
```

```
多界面状态管理
Vue已经帮我们做好了单个界面的状态管理,但是如果是多个界面呢?
多个视图都依赖同一个状态(一个状态改了,多个界面需要进行更新)
不同界面的Actions都想修改同一个状态(Home.vue需要修改,Profile.vue也需要修改这个状态)
也就是说对于某些状态(状态1/状态2/状态3)来说只属于我们某一个试图,但是也有一些状态(状态a/状态b/状态c)属于多个试图共同想要维护的
状态1/状态2/状态3你放在自己的房间中,你自己管理自己用,没问题。
但是状态a/状态b/状态c我们希望交给一个大管家来统一帮助我们管理!!!
没错,Vuex就是为我们提供这个大管家的工具。
全局单例模式(大管家)
我们现在要做的就是将共享的状态抽取出来,交给我们的大管家,统一进行管理。
之后,你们每个试图,按照我规定好的规定,进行访问和修改等操作。
这就是Vuex背后的基本思想。
```
第18步: Vuex状态管理官方图例
上面的代码示例方式:直接简单粗暴的在组件中修改 `$store.state.counter`,如图所示:不建议这么操作
```
缺点:不方便跟踪每一步的状态
```

推荐使用方式:绕个圈来修改状态

```
浏览器中的devtools的作用:监听\跟踪\修改\记录修改后的State状态,避免混乱
解决办法:Vue官方提供/开发的devtools浏览器插件就很方便
可以找到谁修改了此状态,跟踪到此组件,去里面修改就行。
```

第19步: 可以绕过Action直接更改Mutations

第20步:mutations和vuex-devtools
安装插件:

检验插件是否安装成功:

第21步:写一些mutatons相关代码来验证插件生效
```js
// store/index.js
const store = new Vuex.Store({
state: {
counter: 0,
},
mutations: {
// 这里的state就是上面的state对象
increment(state) {
state.counter++
},
// 字符串的事件类型(type) 例如;decrement
// 一个回调函数(handler),该回调函数的第一个参数就是state 例如:(state) {state.counter--}
decrement(state) {
state.counter--
}
}
})
```
使用:App.vue
```vue
App.vue中的内容{{ $store.state.counter }}
```
第22步:总结
```
好的,这就是使用Vuex最简单的方式了。
我们来对使用步骤,做一个简单的小节:
1.提取出一个公共的store对象,用于保存在多个组件中共享的状态
2.将store对象放置在new Vue对象中,这样可以保证在所有的组件中都可以使用到
3.在其他组件中使用store对象中保存的状态即可
通过this.$store.state.属性的方式来访问状态
通过this.$store.commit('mutation中方法')来修改状态
注意事项:
我们通过提交mutation的方式,而非直接改变store.state.count。
这是因为Vuex可以更明确的追踪状态的变化,所以不要直接改变store.state.count的值。
```
第23步:vuex-state单一状态树的理解
```
但是,它是什么呢?我们来看一个生活中的例子。
在国内我们有很多的信息需要被记录。比如
上学时的个人档案
工作后的社保记录,公积金记录,结婚后的婚姻信息
以及其他相关的户口、医疗、文凭、房产记录等等
安全性:在多个系统里面,比如医疗系统,市场监管系统,信用系统,不容易被黑客入侵。
一个系统入侵,其他系统不一定被入侵,保证安全性。全部一个系统入侵就完蛋啦!!
提供就业岗位:
缺点:
低效:
公积金在每个城市账户是不一样的,取出来公积金就很麻烦,需要跑到各个城市里面取。
国家在慢慢完善,在一个城市里面取就行。
麻烦:
这些信息被分散在很多地方进行管理,有一天你需要办某个业务时(比如入户北京、深圳等)。
到各个对应的工作地点去打印、盖章各种资料信息,最后到一个地方提交证明你的信息无误。
这种保存信息的方案,不仅仅低效,而且不方便管理,以及日后的维护也是一个庞大的工作。
需要大量的各个部门的人力来维护,当然国家目前已经在完善我们的这个系统了
国家在某一个系统可以查询到个人所有的信息的,人肉搜索。
这个和我们在应用开发中比较类似:
如果你的状态信息是保存到多个Store对象中的,那么之后的管理和维护等等都会变得特别困难。
所以Vuex也使用了单一状态树来管理应用层级的全部状态。
单一状态树能够让我们最直接的方式找到某个状态的片段,而且在之后的维护和调试过程中,也可以非常方便的管理和维护。
```
如果定义了多个状态树,如下所示,不方便维护,使用一个store就行。
```js
const store = new Vuex.Store({})
const store1 = new Vuex.Store({})
```
第24步:getters的使用
```
在学习getters计算属性的时候,一个数据需要经过变化后再在界面展示时,可以通过计算属性来使用。
这里的getters也是一样的。
```
案例一:平方代码
```js
//store/index.js
const store = new Vuex.Store({
state: {
num: 2
},
getters: {
powerNum(state) {
return state.num * state.num
}
}
})
```
```vue
{{ $store.state.num * $store.state.num }}
{{ $store.getters.powerNum }}
```
案例二:找大于20的学生信息
方式一:使用计算属性
```js
computed: {
// 获取到20岁以上的学生
more20stu() {
// 获取到所有学生对象
// return this.$store.state.students
// 进行过滤 filter\map\redius都讲过
return this.$store.state.students.filter(s =>{
return s.age > 20// 返回一个布尔值,返回为true把s加到新的数组里作为返回值,false就忽略掉
})
// 简写
// return this.$store.state.students.filter(s => s.age = 20)
}
}
// 缺点:组件之间哪里用到就把该组件放到哪一个组件的script里面。
// 比较麻烦,有10个组件就要定义10个一模一样的计算属性。
```
方式二:
```js
// store/index.js
const store = new Vuex.Store({
state: {
students: [
{id: 0, name:'张三', age:18 },
{id: 1, name:'李四', age:19 },
{id: 2, name:'王五', age:20 },
{id: 3, name:'马六', age:21 }
]
},
getters: {
// 获取年龄大于20岁学生
more20stu(state){
return state.students.filter(s => s.age > 20)
}
}
})
```
```vue
{{ $store.getters.more20stu }}
```
案例三:找年龄大于20的学生个数
方式一:
```js
// store/index.js
和方式一的一样,不变
```
```vue
{{ $store.getters.more20stu.length }}
```
方式二:
```js
// store/index.js
getters: {
// 获取年龄大于20岁学生个数
more20stuLength(state){
return state.students.filter(s => s.age > 20).length
}
}
```
```vue
{{ $store.getters.more20stuLength}}
```
方式三:添加第二个参数
```js
// store/index.js
getters: {
// 获取年龄大于20岁学生
more20stu(state) {
return state.students.filter(s => s.age > 20)
},
// 参数二getters就是这一大个getters对象 getters变量是可以改变的,可以改成aaa、bbb
more20stuLength(state, getters) {
return getters.more20stu.length;
}
}
```
```vue
{{ $store.getters.more20stuLength}}
```
案例四:找年龄大于age的学生个数,age需要自己填进去
```js
// store/index.js
getters: {
// 错误方法moreAgestuLength(state,getters,age){}
moreAgestuLength(state) {
// return function (age) {
// return state.students.filter(s => s.age > age)
// }
// 简写
return age => {
return state.students.filter(s => s.age > age)
}
}
}
```
```vue
{{ $store.getters.moreAgestuLength(18)}}
```
第25步:点击按钮加5和加10
方式一:App.vue
```vue
{{ $store.state.counter }}
```
```js
// store/index.js
const store = new Vuex.Store({
state: {
counter: 0
},
mutations: {
incrementCount(state, count) {
state.counter += count
}
}
})
```
方式二:mutation改进,传递多个参数
```vue
{{ $store.state.students }}
```
```js
// store/index.js
const store = new Vuex.Store({
state: {
students: [
{id: 0, name:'张三', age:18 },
{id: 1, name:'李四', age:19 }
]
},
// payload:负荷负载
mutations: {
// 普通的提交风格
addStudent(state,stu) {
state.students.push(stu)
}
}
})
```
第26步:mutation的提交风格
公共部分:App.vue
```vue
{{ $store.state.counter }}
```
原来的打印:
```js
// App.vue
methods: {
addCount(count) {
// 1、普通的提交风格
this.$store.commit('incrementCount', count)
}
}
```
```js
// store/index.js
const store = new Vuex.Store({
state: {
counter: 0
},
mutations: {
incrementCount(state, count) {
// state.counter += count
console.log(count);
}
}
})
```
现在的打印:
```js
// App.vue
methods: {
addCount(count) {
// 2、特殊的提交风格
this.$store.commit({
type: 'incrementCount',
// count: count,
count
// age:18
})
}
}
```
```js
// store/index.js
const store = new Vuex.Store({
state: {
counter: 0
},
mutations: {
incrementCount(state, payload) {
// payload代表App.vue中的 type: 'incrementCount',count}对象
console.log(payload);
state.counter += payload.count
}
}
})
```
第27步:
```
响应式原理:加入Vue的响应式系统里面了。
每一个属性都有一个Dep,Dep对应很多[watcher]
每一个属性对应一个Dep对象
Dep可以监听属性的变化
Dep是观察者模式,一旦数据有变化,就会去改变数据
每一个数组里面放置了好几个watcher,一旦数据有变化,就去告诉watcher,数据变化了,然后一个个的去改变。
在Vuex源码里面有。
```
相关代码:
App.vue:
```vue
{{ $store.state.info }}
{{ $store.state.info }}
```
store/index.js:
```js
const store = new Vuex.Store({
state: {
/*
这些属性都会被加入到响应式系统中
而响应式系统会监听属性的变化,
当属性发生变化时,会通知所有界面中用到该属性的地方让界面发生刷新
*/
info: {
name: '科比',
age: 1979,
height: 1.98
}
},
mutations: {
updateInfo(state) {
// 修改属性
// state.info.name = '和乔丹一样高'
// 添加属性
// 不属于监听范围。单独的这一行是不会刷新的,如果没注释上面第一行代码,就会连带一起刷新
// state.info['address'] = '洛杉矶'
// 解决方法
// 数组的push/pop/等方法是响应式的
// Vue.set(state.info,'sex','男')
// 删除属性 该方式做不到响应式
// delete state.info.age
// 解决方法
Vue.delete(state.info, 'height')
// 总结:原来有的数据,定义好的才能具有响应式,界面会发生改变
// 如果是后来添加删除的属性,是没有响应式的。Vuex插件里面有,但是不会展示到界面上
// 需要使用特殊的语法,才可以进行展示到界面上
}
}
})
```
总结:
```
Vuex的store中的state是响应式的, 当state中的数据发生改变时, Vue组件会自动更新.
这就要求我们必须遵守一些Vuex对应的规则:
提前在store中初始化好所需的属性.
当给state中的对象添加新属性时, 使用下面的方式:
方式一: 使用Vue.set(obj, 'newProp', 123)
方式二: 用心对象给旧对象重新赋值
我们来看一个例子:
当我们点击更新信息时, 界面并没有发生对应改变.
如何才能让它改变呢?
查看下面代码的方式一和方式二
都可以让state中的属性是响应式的.
```


第28步:Mutation常量类型 – 概念
```
我们来考虑下面的问题:
在mutation中, 我们定义了很多事件类型(也就是其中的方法名称).
当我们的项目增大时, Vuex管理的状态越来越多, 需要更新状态的情况越来越多, 那么意味着Mutation中的方法越来越多.
方法过多, 使用者需要花费大量的经历去记住这些方法, 甚至是多个文件间来回切换, 查看方法名称, 甚至如果不是复制的时候, 可能还会出现写错的情况.
如何避免上述的问题呢?
在各种Flux实现中, 一种很常见的方案就是使用常量替代Mutation事件的类型.
我们可以将这些常量放在一个单独的文件中, 方便管理以及让整个app所有的事件类型一目了然.
具体怎么做呢?
我们可以创建一个文件: store/mutation-types.js, 并且在其中定义我们的常量.
定义常量时, 我们可以使用ES2015中的风格, 使用一个常量来作为函数的名称.
```
原来写法:
```vue
{{ $store.state.counter }}
```
```js
// store/index.js
const store = new Vuex.Store({
state: {
counter: 0
},
mutations: {
increment(state) {
state.counter += 6
}
}
})
```
现在写法:
```vue
```
```js
// store/mutation-types.js
// 导出一个确定的常量
export const INCREMENT = 'increment'
//同理可写
export const UPDATE_INFO = 'UPDATE_INFO'
```
```js
// store/index.js
import {
INCREMENT
} from './mutation-types'
// 还可以自己写
// import * as types from './store/mutation-types'
const store = new Vuex.Store({
state: {
counter: 0
},
mutations: {
// 定义increment(){}方法
[INCREMENT](state) {
state.counter += 6
},
// [types.UPDATE_INFO](state,payload){
// state.info = {...state.info,'height':payload.height}
// }
}
})
```
第29步:Mutation同步函数
```
通常情况下, Vuex要求我们Mutation中的方法必须是同步方法,里面的函数是同步函数.
主要的原因是当我们使用devtools时, 可以devtools可以帮助我们捕捉mutation的快照,是有记录的.
但是如果是异步操作, 那么devtools将不能很好的追踪这个操作什么时候会被完成.
```
```js
// store/index.js
import {
UPDATE_INFO
} from './mutation-types'
const store = new Vuex.Store({
state: {
info: {
name: '科比',
age: 1979,
height: 1.98
}
},
mutations: {
[UPDATE_INFO](state) {
// 同步进行修改:最好是同步的
state.info.name = '和乔丹一样高'
// 模拟异步操作(使用了异步函数):弊端-->Vuex插件里面不会出现更新信息
setTimeout(() => {
state.info.age = 44
}, 1000);
// 你会发现state中的info数据一直没有被改变, 因为他无法追踪到.
// So, 通常情况下, 不要再mutation中进行异步的操作
}
}
})
```
```vue
{{ $store.state.info }}
```
```js
// mutation-types.js
export const UPDATE_INFO = 'updateInfo'
```
第30步:解决办法
```
我们强调, 不要再Mutation中进行异步操作.
但是某些情况, 我们确实希望在Vuex中进行一些异步操作, 比如网络请求, 必然是异步的. 这个时候怎么处理呢?
Action类似于Mutation, 但是是用来代替Mutation进行异步操作的.
Action的基本使用代码如下:
context是什么?
也就是说, 我们可以通过context去进行commit相关的操作, 也可以获取context.state等.
但是注意, 这里它们并不是同一个对象, 为什么呢? 我们后面学习Modules的时候, 再具体说.
这样的代码是否多此一举呢?
我们定义了actions, 然后又在actions中去进行commit, 这不是脱裤放屁吗?
事实上并不是这样, 如果在Vuex中有异步操作, 那么我们就可以在actions中完成了.
```
第31步:理解代码
index.js:
```js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
import {
UPDATE_INFO
} from './mutation-types'
const store = new Vuex.Store({
state: {
info: {
name: '科比',
age: 1979,
height: 1.98
}
},
mutations: {
aUpdateInfo(state) {
setTimeout(() => {
state.info.age = 44
}, 1000);
}
},
actions: {
// context是和store对象具有相同方法和属性的对象
// cpntext理解为store对象
aUpdateInfo(context) {
// 错误方法,修改state的唯一方法是mutation
// context.state.info.name = '张三'
setTimeout(() => {
// store里面有commit
context.commit('aUpdateInfo')
}, 1000)
}
}
})
export default store
```
App.vue:
```vue
{{ $store.state.info }}
```
# 五、Vue CLI2
不用记命令,在[官网](https://cli.vuejs.org/zh/guide/creating-a-project.html#vue-create)查询即可。
以后公司开发,最多是随便拉取一遍,更多的是在写代码。
## 1、创建项目
```shell
“创建项目”也叫“初始化项目”,创建项目(脚手架模板)时,会自动下载并生成一些模板。
项目名称不能出现中文:supermall、my-project、tabbar等。
创建方法:
创建一个目录,进入后在地址栏输出cmd。
$ vue init 模板名称 项目名称
$ vue create 项目名称 # 注意:vue create只有3.0以上的版本才可以使用。
Vue CLI3比起Vue CLI2更好用,后面的项目中也使用VueCLI3
模板名称:可选择打包工具
Webpack:将来用webpack打包
grid:
gulp:
上面的命令是从【vuejs-templates/webpack】提取模板:https://github.com/vuejs-templates/webpack
如果安装不了:
1、npm clean cache -force #内部是去清空npm cache
找到该隐藏文件夹npm-cache,该文件夹是npm的全局安装缓存,可以指定其他磁盘。
删除该文件夹。C:\Users\LKW\AppData\Roaming\npm-cache
2、重新安装node
3、以管理员身份打开终端Win+X,才能执行某些指令。
```

```js
1. Project name:真正项目的名称。
不能包含大写,在package.json里面看到的。
例如:myvuejsproject、tabbar、supermall等,和前面创建项目名字一样的。
一般而言文件名字和项目名字一样的,直接回车就默认使用上面创建的名字。
2. Project description:项目描述
默认:A Vue.js project
我们可以重新设置为 test vue cli2,这些信息都会保存在package.json里面的。
3. Author:项目作者,会默认从git中读取信息
之前配置过全局的.gitconfig文件,里面会配置邮箱信息。
也可以自己在这里输入。例如:coderwhy coderwhy@gmail.com
这里选择:敲回车,使用默认原来的信息。
4. Vue build:vue构建项目的构建方式。
Webpack里面使用Vue的时候讲过。以后会详细讲他们之间的区别。
第一种 Runtime + Compiler 运行加编译,想办法指定这个才能正常运行和编译。
官方推荐大多数用户使用这个。暂时先选择上面这个。
第二种 Runtime-only 仅运行。(使用这个)
当时讲Webpack默认使用,很多东西是编译不了的。
以后项目更多使用这个。
大概这个文件会轻6kb,比上面打包出来的程序更小。
运行效率更高。
区别:
2. Install vue-router? :是否安装 vue-router ,这是官方的路由,大多数情况下都使用。
做大型项目,可能会使用Vue的全家桶(Vue的核心VueCore+vue-router+vuex)
是:脚手架自动给安装
否:后面也可再来单独安装。
3. Use ESLint to lint your code?:是否使用 ESLint 管理代码。 否
ESLint 对ES代码进行限制,实际上就是对JS代码进行限制。
JS:JavaScript,是ECMAScript ECMA
ESLint 是个代码风格管理工具,是用来统一代码风格的,一般项目中都会使用。
以后写的JS代码变的非常规范,只要写的不规范,编译、编译器、IDE就会报错。
//自己写的很规范
function abc (){
}
//别人写的可能不规范 格式语法很不规范
function abc () {
const name= '张三';
const age =18;
}
直接编译不通过,自动检查出来,代码写的太不规范了。
我们暂时不用它,选择y,后面写代码可能不用它了,现在就演示一下。
用它很多时候不习惯,我们一般都不用它。可以选择n。
//函数自己的习惯,不是标准的,就容易报错
function abc() {
}
(1)上面选择了yes,下面就要选择一种规范。
1. Pick an ESLint preset:选择一个 ESLint 预设,编写 vue 项目时代码风格,选择 Standard (标准)即可。
● 自己配置一个规范:最后可能谁的不用,按照自己的规范去写。
● 标准规范(我们这里先使用这个):Standard -----------ESLint标准规范
● 另外一些公司的规范:Airbnb规范----------做民宿的,国外的公司的规范。
大公司,里面的很多规范都会作为前端的规范。
Airbnb公司有Airbnb软件,可以定一些房间。
Airbnb公司对React的贡献是很大的。
上个月官宣:大公司的决定也是一个风向标。
安卓APP和IOS的APP要React Native开发,以后不要React Native(要学习)开发。
全部转原生开发,因为React开发没有原生开发。接近原生但是终究是没有原生好。
IOS:使用OC或者Swift开发
安卓:使用Java开发
(2)Setup unit tests:是否安装单元测试,选择安装即可。直接选择n即可。
会依赖一些第三方的测试框架。
国内写单元测试的公司相对很少。80%-90%的公司都不写单元测试。
单元测试里面就是很多的段元,对很多单独的模块进行测试。
(3)Pick a test runner:选择一个单元测试运行器,选择 Jest 即可。
(4)Setup e2e tests with Nightwatch? :是否安装 e2e 测试框架 NightWatch 。这里我们选择n
e2e,也就是 End To End,端到端测试,会写一个自动化测试的一个框架。就是所谓的“用户真实场景”。
国外资料常见:把e to e 写成e2e
这里的端到端测试是想依赖于Nightwatch。
Nightwatch会结合selenium来使用,可以直接测试出来一套的端到端测试的一套代码。
以后整个项目可以直接在浏览器上进行自动化测试。
以后按钮的点击跳转不需要手动点击测试,直接Python自动测试。
测试高级工程师都是写代码自动测试,不是手来点击测试的。工资比开发的还高。
4、Should we run npm install for you after the project has been created?:项目创建后是否要
为你运行“ npm install ”。
熟悉npm就使用npm。
就是一种管理工具,熟悉那个用哪个。
5、安装 会出现一些警告不用管它。
```

## 4、运行项目
```shell
区分VueCLI2还是Vue CLI3创建项目的方法:
方法一:看是否有build目录、config目录,有的就是Vue CLI2,没有的就是Vue CLI3
方法二:看package.json中是否有serve还是dev,有dev的就是Vue CLI2,有serve的就是Vue CLI3
$ npm install
$ npm run serve # Vue CLI3 执行package.json中script中serve后面的命令 vue-cli-service serve
$ npm run dev # 执行package.json中script中dev后面的命令
$ npm run build # 编译,打包构建
$ npm run test # 测试
$ npm run lint # 代码检测
```
# 六、Vue CLI3
Vue CLI3官方文档:https://cli.vuejs.org/zh/guide/creating-a-project.html#vue-create
Vue CLI3的升级并不意味着Vue2的升级。即Vue2的代码也可以使用Vue CLI3这个工具。
> Vue2中加入类型检测,float-type是Facebook的东西。
>
> Vue3中不打算float-type,打算转向TS(Microsoft微小micro软件soft),Vue3里面的源码都是打算使用TS来写。
## 1、选择预设
```shell
? Please pick a preset: (Use arrow keys) # 选取一个预设
# 自己保存的预设,也是最简单的预设
# 这个我们可以暂时不用选择,可以以后用到的时候,再去安装,再去添加
> likewei ([Vue 2] babel)
# 默认添加两个管关键东西:基本的Babel + ESLint 设置,会默认安装这两款校验工具。
# Babel:ES6转ES5的
# 也包含一些基础的,例如:vue-loader . . . . . .
Default ([Vue 3] babel, eslint)
# 第一次官方默认搭建方案。
Default ([Vue 2] babel, eslint)
# 手动选择(配置和安装)需要的更多特性,例如:vue-router、vuex等
Manually select features
# 包含一些信息和依赖,它们是面向生产的项目更加需要的。
# 后期我们可以自己搭建方案可以更加丰富的选择。
# 自己配置的可以选择这个,以后用到什么再继续加。
# 选这个简单的不会生成乱七八糟的目录机构。
# 安装是需要时间的,是从git上把人家的脚手架默认的项目拉取下来。
```
```shell
Check the features needed for your project: (Press to select, to toggle all, to invert selection, and to proceed) 选择项目中需要的东西。
(*) Babel---------------codewhy老师只选择这个
( ) TypeScript 项目中要用到就选择。相当于ES的超级,里面语法很多,和Java很像,例如:有接口、泛型等语法
( ) Progressive Web App (简写PWA) Support 开发出来的APP会很先进。
原来的APP:
想本地进行存储是比较困难的。更多的使用session-storage来存储,但是效率低、存储的东西有限。
现在配置的APP:
现在配置的APP:
PWA可以缓存很多东西,存储大额的东西。
拥有推送通知,手机微信发过来消息有推送通知。
里面包含很多东西
(*) Vuex 状态管理
(*) CSS Pre-processors---------------------------CSS预处理工具:less/scss/style-less
(*) Linter / Formatter------------------------------Linter就是ESlint,对代码进行检测
( ) Unit Testing------------------------------单元测试
( ) E2E Testing------------------------------端到端测试
上下键可以切换,多选(空格选择)一个CSS、Vuex、Router,然后回车即可。
安装脚手架的依赖、配置脚手架、自动添加依赖等。
```
```
? Choose a version of Vue.js that you want to start the project with 选择vuejs的版本
3.x 3版本依赖于Typescript 脚手架是可以向下兼容的,3.x版本兼容2.x版本
> 2.x 现在使用的都是2.x版本
```
```
Use history mode for router? 是否使用历史模式?是否使用history模式的路由?
Requires proper server setup for index fallback in production (Y/n) Y 是否都行 Y是哈希模式
否:出现一个哈希值,前面带一个#,不好看。vue router是没有#号的。
路由里两种模式:
哈希模式:之前默认使用的哈希模式
历史模式:没用过
```
```
选择css预处理器,根据需求选择。选哪个都行。
CSS Pre-processors 三种CSS预处理语言
Sass/SCSS (with dart-sass) 选择这个也行,因为dart比node下载速度更快
> Less 波哥选这个
Stylus
```
```
选择ESLint规则,这里我选的ESLint with error prevention only
? Pick a linter / formatter config: (Use arrow keys) formatter格式、规则
> ESLint with error prevention only 语法校验最简单,最不严格,其他的语法校验相当严格
ESLint + Airbnb config
ESLint + Standard config 标准配置
ESLint + Prettier
```
```
保存文件时lint 还是提交的时候 ,这里我选的保存文件
? Pick additional lint features: (Press to select, to toggle all, to invert selection, and to proceed) 希望什么时候做语法校验??
>(*) Lint on save 保存文件的时候
( ) Lint and fix on commit 提交的时候
```
```json
? Where do you prefer placing config for Babel, ESLint, etc.? (Use arrow keys)
你希望你的配置作为一个单独的文件存在吗?
bable,postCss,ESLint,这些是放在专用配置文件中,还是放在package.json里,选第一项
> In dedicated config files
保存在一个单独的配置文件里面,方便管理。
上面选择的babel、ESlint配置专门放一个配置文件里面。
一般选择这个。
In package.json
把配置文件放到package.json里面。
package.json文件中最后面是可以放置一些配置文件的。
//例如package.json
"engines":{
"node":">= 6.0.0",
"npm":">=3.0.0"
},
"browserslist":[
"> 1%",
"last 2 versions",
"not ie <= 8"
]
```
```json
Save this as a preset for future projects?是否要保存作为将来的预设? (y/N) N不保存
保存预设:
留着下次用。
生成一个common配置,下次在开始的时候,就会有一个2.x 3.x common的选择。
需要填写保存名字。Save preset as:likewei
选择npm还是yarn:这里可以选择npm
删除预设方法:
C:\Users\LKW\.gitconfig 全局gitconfig配置文件
C:\Users\LKW\.npmrc npm默认的东西
rc来源于Linux,在终端里面敲命令并保存的文件会保存rc的后缀名
C:\Users\LKW\.vuerc
打开此文件删除对应的配置就行
大部分工具,例如;git工具、vue工具生成的全局配置文件都在C:\Users\LKW\
{
"useTaobaoRegistry": false,
"packageManager":"npm",
"presets":{
"coderwhy":{
"useConfigFiles":true,
"plugins":{
"@vue/cli-plugin-babel":{}
}
},
"likewei":{
"useConfigFiles":true,
"plugins":{
"@vue/cli-plugin-babel":{}
}
}
}
}
不保存预设:
如果选择下次还要重新设置一遍。
因为每次使用的东西不一样,所以就N。还能练手。
选择这个,开头第一步默认的可以使用这个配置。
创建项目,自带一个Git仓库,本地库也初始化成功了。
会自动生成一个本地的.git仓库。
不要可以删除。
执行git init即可生成该文件夹。
安装脚手架的插件 CLI plugins
安装依赖:
拉取2.x模板的时候,之前的资源、模板在Github上放
拉取3.x模板的时候,现在拉取的资源、模板在npm上放着,安装的时候会自动直接下载,不会出现问题。
```
# 案例
## 1、计数器案例
要求:点击 +之后,计数器+1,点击 - 之后, 计数器 -1
```html
当前计数:{{Num}}
```
总结: 原来做法1.获取到button元素,2.添加监听事件
## 2、Vue列表展示
# 七、Vue3
```
出去干开发,Vue2还是一个比较主流的版本。
Vue3是未来的一个趋势。
Vue2太老了,Vue3迟早会成为一个主流。
```
## 1、Vue3的简介
```
Vue (发音为 /vjuː/,类似 view) 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 avaScript 构建,并提供了一套声明式的、组件化的编程模型,帮助你高效地开发用户界面。
无论是简单还是复杂的界面,Vue 都可以胜任。
2020年9月18日,Vue.js发布3.0版本,代号:One Piece(海贼王)
耗时2年多、2600+次提交、30+个RFCs、600+次PR拉取请求、融合99位贡献者的力量。
(1)2600次提交:https://github.com/vuejs/core/graphs/commit-activity
(2)RFC:请求修改意见稿。
一个开源的库,想要维护的更好,需集百家之长,征求团队内部意见以及社区呼声。
请求修改意见稿由团队内部进行维护,不是内部可以维护的,尤雨溪来采纳哪一个意见稿,移除哪一个意见稿。
30+个RFCs:https://github.com/vuejs/rfcs/tree/master/active-rfcs
例如:
composition-api.md意见稿
一般这些30个意见稿一般是一个markdown文档。
开始研究时间:2019-07-10 团队内部就已经发现内部有问题了。
准备很早的,所以可能现在就已经在研究Vue4了,已经就在筹备了,只是我们不知道而已。
该文件里面描述:原来怎么不好?怎么不好?形成代码、对比图来解释!
(3)600+次Pull Request:https://github.com/vuejs/core/pulls?q=is%3Apr+is%3Amerged+-author%3Aapp%2Fdependabot-preview+
(4)99位贡献值:https://github.com/vuejs/core/graphs/contributors
只有99位,确定的,不是100位,不是102位。
下图是贡献的一个排名:
```

```
打开Vue3官网:也是官宣,但是不及时的官宣。
下面这个才是最及时的官宣:
github上的tags官宣地址:https://github.com/vuejs/vue-next/releases/tag/v3.0.0
tags:一个公开的开源库,想要发布新版本,必须把目前所写的代码形成一个里程碑版本。
例如:
我写了100多个文件,200多次修改,终于把Vue3写完了。
最终得把100多个文件,200多次修改等等,得把这些东西进行一次打包。
形成一个版本,何年何月何日,发布什么版本,包含什么功能。
```
```
https://github.com/vuejs/core/releases
打开Tags,可以看到很多其他的版本。
```

但是,滑到3.0.0版本,大版本,里面有很多改动,里面肯定有很多描述:

## 2、Vue3带来了什么
### 2.1 性能的提升
```
打包大小减少41%:
使用Vue3写比Vue2写大小少41%。------少
初次渲染快55%, 更新渲染快133%
速度比原来快。------快
内存占用减少54%
...........
```
### 2.2 源码的升级
```
使用Proxy代替defineProperty实现响应式
学过defineProperty,来使用Proxy学起来更快,差异不是很大。
好比:学过自行车,去学摩托车,一样学的快。
我们只关心,一改数据,页面就发生改变————响应式的,不关心内部源码怎么写的。
Proxy怎么来实现的(面试题):写代码来看一下。
重写虚拟DOM的实现和Tree-Shaking
(1)让虚拟DOM的对比更加快了,升级了一下算法。
(2)Tree-Shaking:可以在MDNh中搜索Tree-Shaking
Tree-Shaking不是window上的一个属性/方法,就是一个术语,即术语表。
Tree-Shaking:大树摇起来。树龄很高,抱住摇落下来的都是无用的枯枝败叶,健壮的树枝都留在大树上。
生活中的Tree-Shaking是干掉枯枝败叶。
编码中的Tree-Shaking是剔除掉没有使用到的代码。
例如:实现某个功能,引入一个重量级库,但是实际上只是用到里面的一丢丢东西。
经过Tree-Shaking,就可以把这个重量级库里面没有使用到的代码摇到了,让打包体积变小。
Tree-Shaking是一个术语,自己想要实现,自己写代码。
webpack本身就支持Tree-Shaking。
Tree-Shaking:https://developer.mozilla.org/zh-CN/docs/Glossary/Tree_shaking
..........
```
### 2.3 拥抱`TypeScript `
```
Vue3可以更好的支持TypeScript---微软出的脚本语言TS。
Vue3众多亮点中最吸引人的一个,最打眼的一个。
TypeScript以后肯定是一个拥抱TS的前端时代,未来的趋势。
TypeScript是强类型的,Vue3里面更好的支持TS。
Vue2也可以写TS,但是配置起来比较麻烦,没有官方给自己一些渠道,自己配置一些loader,比较麻烦。
本套课程不会使用TS来写Vue3的东西。TS+Vue3教程就是使用TS来写的。
TS不难:
对类型进行一方严格的校验
接口
泛型
```
### 2.4 新的特性 (面试题)