笔记来源于慕课网视频https://coding.imooc.com/class/chapter/94.html#Anchor 老师 JoJozhai 纳斯达克上市公司技术总监,创业公司CTO
在angular4 中,较少组件之间的耦合,提升组件的可重用性的方法有:组件之间通讯的输入和输出属性,依赖注入等。
一、angular4 课程介绍和简介
- 课程介绍
angular1 叫 angularjs angular4 以后都叫angular(谷歌开发,用微软的typescript 来编写的,在环境搭建 组件讲解可以知道) ,约定俗称
之前的szh 做的消息通知其实可以用websock 协议来解决,不用隔几秒来请求一次
慕课网最近也推出了自己的代码仓库,git.imook 课程的源码在那里可以看到
2. 简介
对比 angularjs 和 angular (架构对比)
angualrjs 是前端典型的mvc 架构,下面有顺序。
![](https://img-blog.csdn.net/20180904100652723?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
angular 架构采用完全不同于angularjs 的方式
![](https://img-blog.csdn.net/20180904100915130?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
angular新特性
1.全新的命令行工作AngularCLI
2.服务器端渲染
3.移动和桌面的兼容
4.性能更快(因为在传统的angularjs 里面 ,默认采用的是双向绑定,但是在angular4 中默认的都是单向绑定,不论是事件绑定,属性绑定,插值绑定等,双向绑定只是其中的一个选择,这就大大的加快了速度)
二、angular 开发
- 内容介绍
就是下面的东西
- 程序架构
1、angular程序架构
2、组件:可以理解为一段带有业务逻辑和数据的html,组件可以包含父子关系,组件可以调用逻辑。
3、服务:用来封装可重用的业务逻辑
4、指令:允许你想htmluansu添加自定义行为
5、模块:用来将应用中不同的部分组织成一个angular框架可以理解的单元。
总结:组件、服务、指令是用来完成功能的,而模块是用来打包和分发的。
- 搭建环境
1.环境(nodejs,angular cli ,webstorm)
官网下载node.js(因为要用npm)-下载完成后npm下载@angular/cli (ng -v 出现版本号表示安装完成,注意ng 这也就解释了为什很多在npm 的 angular 的包都是ng 开头的,然后利用这个脚手架去开发angular 的项目,具体的命令自行百度) 编辑器用webstorm
![](https://img-blog.csdn.net/20180904102618417?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
项目目录(简单没写)
组件讲解
angular 是用typescript 来编写的,下图的appcomponent 是一个典型的typescript 的类,上面的@component 是下面紧跟着的类的组件的属性装饰器,来形容这个组件,因为angular 是不认识这个类的,用属性装饰器来告诉angular 他是angular 的一个组件。
![](https://img-blog.csdn.net/20180904110536320?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
![](https://img-blog.csdn.net/20180904110324515?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
模块讲解
-
@NgModule 模块装饰器(让angular 识别这个typescript 的类)
1. declarations中只能声明组件、指令和管道
2. imports引用当前模块依赖的其他模块
3. providers声明模块提供的服务,只能声明服务
4. bootstrap声明模块的主组件
- angular 的启动过程
自我提问:启动的时候加载了哪个脚本文件? 启动的时候加载了哪个 html文件?
![](https://img-blog.csdn.net/20180904143113298?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
这是angular.cli 文件,里面定义了一些基本的信息,比如说我们开发的root目录是是src ,那么加载的首个html就是src/index.html,首个的脚本文件是就是src/main.ts。比如说name 就是网页卡片的title
![](https://img-blog.csdn.net/20180904145830389?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
首先会根据main.ts 加载里面的模块----根据main.ts 在加载启动模块appmodule---在加载appmodule里面依赖的模块和组件(如果依赖的模块里面有其他的模块也要加载)---最后在index.html 里面找到appmodule 声明的组件的选择器app-root。
上面就是加载的过程,如果在index.html 这么写<app-root>Loading...</app-root> 那么在页面上首先看到就是load... ,然后才是在根组件里面通过绑定到模板的值。这就是 因为加载的过程需要一定的时间。
- 开发准备
整个课程不是自己一行行的代码开发的,而是基于github一个开源的框架AdminLTE(通过github 可以找到它的官网地址,官网有项目的开发文档,这里复制的是开发文档中起始页面的body,文档也讲到了如何改变皮肤等等,所以如果有时间可以仔细的去研究下)。但是没有找到之前的angular4 这个开源框架(之前的angular4 估计也会是类似的这个框架,官网有的很多,花钱购买的其中一个),但是不要紧有zorror就够了。之前我们在做项目的时候也是基于angular4 整个框架开发的。在angular 的官网的资源会看到更多的ui,比如zorror。
在编程届有句俗话就是,你和大牛的差别就在于 一个Github。
然后引入样式和js和图片就可以了。
- 开发项目组件上
也是复制AdminLTE代码 在git.imook 可以看到源码
- 开发项目组件下
三、angular 路由
- 路由内容的介绍
![](https://img-blog.csdn.net/20180905071452712?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
spa:single page application 单页应用;angular应用就是spa;可以把一个angular应用看做一组视图状态的集合,没有路由指向每个特定的视图状态,每次打开只需要加载新的内容,公共部分不用重复加载,这样大大节省流量。如果是传统的打开新的窗口会重新加载js等。
SPA:单页应用其实一次性全部加载完,angular指的就是index.html页面,然后通过路由对象来实现各个组件间的切换,大大提高页面的访问效率。对于我们的adminLTE后台管理系统界面,如果我们只想要让中间的内容组件的位置发生改变,那我们就在那里设置插座。你可以理解为生活中的插座,同一个插口,插完电脑插电视。
-
-
路由基础
![](https://img-blog.csdn.net/2018090507205037?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
routes: 在配置的时候不用加'/',配置在模块中必须配置:1. path 2. component , 通配符**路径配置,放到最后!如果放到最前面,直接走的就是这个
routerOutlet:显示哪个组件。浏览器的开发者工具可以看到不同的路由在routerOutlet下面会显示不同的组件
router:写的时候用数组,因为以后还要传递参数。
routerLink:写的时候用数组,因为以后还要传递参数。
activatedRoute:在下面的路由时候传递参数时候讲,因为传递参数时候会携带数据,用这个可以拿到携带的数据。
![](https://img-blog.csdn.net/20180905072254808?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
在ng new 生成新的项目的时候可以加一个--routeing 会生成一个app-routing.module.ts 并且自动导入到app.module.ts
也可以写一个router.ts 并且 RouterModule.forRoot(routes, {useHash: true}),
如果不加hash ,在服务器上的时候会报错
- 在路由时传递数据
1.在查询参数中传递数据
![](https://img-blog.csdn.net/20180905075436367?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
![](https://img-blog.csdn.net/20180905080236730?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
2.在路由的路径中传递参数
![](https://img-blog.csdn.net/20180905075520313?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
![](https://img-blog.csdn.net/2018090508031234?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
![](https://img-blog.csdn.net/20180905080344431?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
3.在路由的配置中传递数据
![](https://img-blog.csdn.net/20180905075601239?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
![](https://img-blog.csdn.net/20180905081350270?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
注意:参数快照和参数订阅的区别
快照snapshot,只是在组件初始化的时候会赋值,如果是股票详情到股票详情就有问题了,因为组件还是详情组件,组件没有更新。
订阅就不一样了,会一直执行,但是影响性能,快照只是赋值一次,所以比较快。
如果确认不会由详情到详情就可以用快照
![](https://img-blog.csdn.net/2018090508120666?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
- 重顶向路由
![](https://img-blog.csdn.net/20180905081814544?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
![](https://img-blog.csdn.net/20180905082129956?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
![](https://img-blog.csdn.net/20180905082144556?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
一般都是上图那样,路由的名字和组件的名字是一样的,所以有了重定向路由,pathMatch :full 的意思是完全匹配。
- 子路由
这是一种写法还有另外一种写法是children:另外一个routes
-
辅助路由(使用于不管页面怎么跳转一直都存在的东西)
![](https://img-blog.csdn.net/20180905083954330?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
-
路由守卫(说白了就是路由的拦截器,其共同点是:1.都需要注入 2.都是返回true执行,false 不执行)
![](https://img-blog.csdn.net/20180905091130308?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
canactive守卫 进入到某个组件时判断,比如有价值的信息不想让游客看到
![](https://img-blog.csdn.net/20180905092145903?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
candeactive守卫 和canactive 的区别在于,他是离开时候的操作,所以知道当时的组件是什么
![](https://img-blog.csdn.net/20180905092019990?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
![](https://img-blog.csdn.net/20180905092312465?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
共同点:需要在provides里面实例化,不能直接用类。
- resolve 守卫
![](https://img-blog.csdn.net/201809050937209?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
![](https://img-blog.csdn.net/2018090509375056?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
![](https://img-blog.csdn.net/20180905093847896?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
注意事项:
1.一定要讲守卫注入实例化
2.这个可以应用到我们请求后台的数据,在手为例当所有的数据拿到后才返回true。这样可以防止页面报错。
- 改造股票管理的应用
让菜单是选中的状态(可以把当前的id存储起来和所有的进行对比,如果一样就加上这个样式)
![](https://img-blog.csdn.net/20180905100710315?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
根据浏览器路径的不同,公共的地方显示不同的东西(这是响应式编程的rxjs,在深入学习里面会讲到),当然也可以用location![](https://img-blog.csdn.net/20180905101155870?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
四、angular 依赖注入
- 依赖注入内容介绍
- 依赖注入的好处
1.松耦合,可重用
下图中的1等价于2 意思是这个模块提供一个tocken (就是2中的provide)为ProduceService,如果有人要用这个tocken了,那么久实例化(useClass)后面的那个类
构造函数里面写的就是我要用这个ProduceService 这个tocken了。
2.可测试
- 提供器入门
angular4 是如何实现依赖注入的
1.注入器 2. 提供器(提供器会把所有需要实例化的类都实例化好,放到一个池里面并且配有tocken,注入器在用的时候根据tocken 来用就可以了,可见5下面的等价,其实等价拿的是tocken)
![](https://img-blog.csdn.net/20180905104524285?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
提供器的作用域:
1.在跟模块的提供器,全局的组件都是可以用的。
2.在组件中注入的组件,仅仅在当前组件中及其子组件可以使用。
3.当在组件当中提供器的tocken和模块中的tocken一样的话,组件的提供器的优先级是高于模块的优先级。
![](https://img-blog.csdn.net/20180905105646121?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
提供器的三种声明方法:useClass、useFactory、userValue
注意事项:
这个类上面加了@injectable,说明他是可以注入其他服务的。@component 继承了@injectable,所以说在组件中可以直接注入很多服务。
- 使用工厂和值声明提供器
使用工厂方法创建出来的对象是一个单例对象,也就是说,只会在创建第一个对象时被调用一次,其余的都是使用同一个对象。
![](https://img-blog.csdn.net/2018090511105815?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
在提供器里面写入提供器(下图,上图的问题在于在工厂函数里面又去实例化了loggerservice这就增加了耦合,解决办法是下图,在这个提供器的后面写个deps,值是数组,数组里面都是工厂函数中参数 要使用的提供器的tocken),较少耦合。
提供器的三种声明方法:useClass、useFactory、userValue(变量或者是对象被依赖注入),用法如图
- 注入器以及层级关系
angular4 的提供器可以在模块里面,也可以在组件的属性装饰器里面(因为这样也就形成了一个层级)
angular4 注入器的话只有一个地方,只能是在构造函数里面,注入器首先会找自己组件的提供器然后是父组件,根组件,跟块,根模块。
![](https://img-blog.csdn.net/20180905114044324?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
![](https://img-blog.csdn.net/20180905113838871?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
等价于下面,
- 改造项目
见git.imook
五、angular 数据绑定,响应式编程和管道
- 整章的内容介绍
数据绑定,响应式编程 和 管道
- 事件绑定
大多是单向绑定,将控制器里面的属性或者是方法绑定到模板里面。angualrjs 里面默认是双向绑定,这就影响了性能。
在angular4 中除非特别指明是双向绑定,这就大大加快了速度。
![](https://img-blog.csdn.net/20180905142941932?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
- dom 属性绑定
需要澄清的概念
1.插值表达式和dom属性绑定其实是一个东西,插值表达式最后也都转化成了属性绑定 。只不过插值表达式更加方便而已,在代码编写的时候我们只要尽量保持一种风格就可以了。
2.dom属性绑定和html属性的区别(可以看下图的dom 属性绑定)
html属性就是初始化dom属性,dom属性是会一直变化的,但是 html属性是不会变化的。angular操作的是dom属性
![](https://img-blog.csdn.net/20180905151136802?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
下面的是一个特殊的,设置disable 的值是true还是false 都是不管用的,只要设置了disabled 就是禁用,但是可以通过设计它的dom 属性来改变。
![](https://img-blog.csdn.net/20180905151545944?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
下图就是dom 属性绑定,因为angular 是和dom 打交道的。
![](https://img-blog.csdn.net/2018090710024012?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
![](https://img-blog.csdn.net/20180905153345950?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
![](https://img-blog.csdn.net/20180905153414365?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
- html 属性绑定
因为有的属性只能是用html属性绑定,比如colspan,因为它没有dom属性。
![](https://img-blog.csdn.net/20180905180643990?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
![](https://img-blog.csdn.net/20180905180731818?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
![](https://img-blog.csdn.net/20180905180815890?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
![](https://img-blog.csdn.net/20180905181813387?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
- 双向绑定
事件绑定是由模板到控制器,单向
属性绑定是控制器到模板,单向
双向绑定呢,就是把上面的两个结合起来。
- 响应式编程(在高阶课程会详解)
响应式编程是以观察者模式为核心的,什么是观察者模式呢?
观察者 模式是由两个对象组成的,一个是可观察对象,另外一个是观察者,一般在初始化对象的时候,我们会像可观察对象注册一个观察者对象,当可观察对象发生变化的时候就会调用观察者里面的一些方法,来把自己的一些变化告诉 观察者,让观察者去做一些事情。这样的模式就叫做观察者模式。
observable 来自于rxjs,rxjs 在我们安装项目的时候就默认的就有
![](https://img-blog.csdn.net/20180906081251325?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
模板引用变量 必须得用 #声明,也可以在div等其他的标签上使用 模板输入变量在let ngfor 循环中![](https://img-blog.csdn.net/20180906083049863?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
模板引用变量 ( #var )
模板引用变量通常用来引用模板中的某个 DOM 元素,它还可以引用 Angular 组件或指令或Web Component。
所以说上面那样写和下面是不一样的
<input #myField='ngModel'></input>
myField如果没有绑定ngModel,只有表单的属性和方法,但是如果绑定了,就有formControll 的这个数据模型的属性和方法。
这样的一个需求,等500毫秒后才进行搜索,首先要引入reactiveformModule,每一个form会有一个valuechange事件。在angular 中 一切皆可以用流来处理。
![](https://img-blog.csdn.net/20180906084923506?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
- 管道
data (可以接收收参数)管道 uppercase 大写,lowercase 小写;
{{birhdaty | data:'yyyy-MM-dd HH:mm:ss'}}
注:yyyy 四位的年,MM:2位的月 dd:天 HH: 24小时制,hh:12小时制 mm:分钟 ss:秒
{{pi|number:'2.2-4'}}
2位整数,最少2位小数,最多4位(多省少补)
管道, | , async 处理异步流
自定义管道简单没写
- 实战
前台自行做搜过功能,不需要请求接口
![](https://img-blog.csdn.net/2018090609084273?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
![](https://img-blog.csdn.net/20180906090858931?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
管道
六、组件间通讯
- 内容介绍
- 输入属性
比如键盘,不用关心她和显示屏是怎么操作的,只是对外提供按键进行输入。对外提供一个接口,和注入一样减少耦合,提高可重用性。
![](https://img-blog.csdn.net/20180906093804333?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
父子组件的数据传递可用输入属性和输出属性。也可用路由传递参数。
- 输出属性
![](https://img-blog.csdn.net/20180906093812804?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
![](https://img-blog.csdn.net/2018090609415536?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
下图只能是$event,这里的$event 代表的是stockinfo,这里(searchResult)是上面的@output()下面的事件名,必须一致,当然也可以在@output()的括号里面顶一个一个事件的别名,事件用别名也是可以的。
- 中间人模式(中间人可以是一个组件也可以是服务)
上面提到的是父子组件之间的通讯,例如2 和 4 ,但是4 5 之间怎么去通讯呢,这就用到了中间人模式,2 就是45 的中间人,1 是最顶级的中间人。
其实很简单,就是2个父子组件的传递,减少耦合,提高可重用性。
- 组件的声明周期钩子概述(9个)
红色的触发一次,绿色的触发多次
组件被创建后会加入到dom树,然后被浏览器渲染出来被用户看到,当组件的属性发生变化的时候被重新渲染出来。利用这些钩子可以在特定时段去拿到特定的数据。
钩子总的来说是三个阶段,组件初始化阶段,变化检测阶段,组件销毁阶段。
带有check 的钩子只要发生任何变化就会执行,所以在使用的时候一定要当心。
![](https://img-blog.csdn.net/201809061008126?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
调用顺序
- onchanges 钩子
作为子组件,在父组件初始化或修改子组件输入参数时触发ngonchanges钩子
理解要点:可变对象和不可变对象
字符串是不可变对象-指向的内存地址变化了
对象是可变对象-指向的内存地址没有变化,内容变化了
之所以用要理解这个是因为,不是所有的输入属性的变化都会触发ngonchange钩子,只有当不可变对象变化的时候才会调用,因为angular 检测到了内存地址的变化,但是会发现子组件的可变对象虽然没有调用,但是他的值也变化了,这是因为angular的变更检测机制下面会讲到(确切的说是ngDocheck钩子)
姓名是对象,问候语是字符串
![](https://img-blog.csdn.net/20180906105120985?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
既然是输入属性参数发生了变化就可以获取变化通过下图的changes
- 变更检测和docheck钩子
变更检测机制
angular4 的变更检测机制是有zone.js 这个包实现的,默认安装的有。作用是保证属性的变化和页面的显示是同步的。变更检测机制会把值的变化反应到模板上。
![](https://img-blog.csdn.net/20180906110406921?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
变更检测的策略有两个 1. defaul 策略 2,onpush 策略
比如说在星那里有个点击事件,zone.js 会把整个的组件树全部都检查一遍,这就是默认的default 策略,如果在某一个组件设置onpush 策略的话,他就不会往下检测。
docheck 钩子在用的时候一定要加判断,如果一直请求后台服务的话受不了。
- view 钩子
首先了解一个知识点,父组件是如何调用子组件的属性和方法的,以下是2种方法
1.在ts 中调用
![](https://img-blog.csdn.net/20180906112631202?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
child1 就是子组件的引用,他有子组件的所有属性和方法。
![](https://img-blog.csdn.net/20180906112710802?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
2.在模板中调用
![](https://img-blog.csdn.net/20180906112926463?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
|
父子组件的执行顺序,先是子组件然后是父组件
![](https://img-blog.csdn.net/20180906114619842?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
afterview 属于在视图组装完成之后的钩子,如果视图组装完成之后再去跟下图一样改变属性的值就会报下图的错误,解决的方法也很简单,加个延时,让他处于js 的 另一个周期中。
![](https://img-blog.csdn.net/20180906114136375?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
-
ngcontent 指令
先理解投影
有这么一个需求,父子组件,字组件有个红框的样式,想要红框里面的内容标签是由父组件传给他的,怎么做?
1.路由来做,在子组件配个路由插座。麻烦,不推荐
2.用innerhtml来做,父组件给子组件一个输入属性。麻烦
3.用投影,推荐。(常用于轮播图,上拉加载 ,下拉刷新等)
父组件在子组件的标签里面写就可以了
![](https://img-blog.csdn.net/20180906143318911?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
子组件加ng-content ,表示投影点。
![](https://img-blog.csdn.net/20180906143333128?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
多段的投影,注意不需要真的在css 中写这么一个样式,只是一个标示位。
![](https://img-blog.csdn.net/20180906144208273?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
- 最后的钩子
afterconteinit aftercontcheck 顺序是先父组件后子组件和视图正好相反(这两个钩子是上面,当有投影内容的时候会触发。并且在这两个钩子里面可以更改属性的值,和view 不一样,因为这时候视图并没有组装完成,投影钩子完了之后才是视图初始化)
- 实战
@input 和@output 写法最好一直,比如如下,这样就可以用双向绑定了,如下图
![](https://img-blog.csdn.net/20180906150320136?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
- 小结
![](https://img-blog.csdn.net/20180906153714375?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
七、表单处理(一开就推荐使用响应式表单,模板式表单处理简单的场景可以)
https://blog.csdn.net/github_39319000/article/details/81144483 另外一篇博客
https://www.cnblogs.com/yulei126/p/6804104.html
响应式表单
1.下拉框可以做,因为下拉框是对象
2. 多选也可以做,但是要记住是formarry,没有key
3. 单选在做的时候就报错了,不知道为什么,暂时用js或者是模板驱动的方式来实现。
- 内容介绍
- 简介
需要在ngModule中引入:
FormsModule:对应模板式表单
ReactiveFormsModule:对应响应式表单
![](https://img-blog.csdn.net/20180906155251440?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
- 模板是表单
form 表单之前如果提交的话会跳转到一个新的窗口,但是npm run start 启动了这个项目后,就由angular接管了这个表单,自动在form 上面添加了ngform 来接管了这个表单,所以说在点击的时候不会跳转,angualr 是spa。因为button 的submit 事件不管用了,模板式表单在form上添加了一个ngsubmit事件来提交,响应式表单在form上添加了一个submit事件来提交,有没有加ng是模板式表单和响应式表单一个重要的区别。模板式表单都可以用模板 引用变量来引用,响应式不可以,其实从名字也可以看出来嘛,是模板本地变量。 form自动添加ngForm,而且会自动发现添加了ngModel指令和name的子元素,并将他们的值添加到表单数据模型中;
注:1.ngForm可以在form之外使用,如div;
2.如果不希望form被自动处理,可以加一个ngNoForm;
3.ngModel是表单字段的指令,需要另加name,作为表单数据模型的key,从而获取value,可以用模板本地变量来引用
#myNickName="ngModel" ngModel name="nicknam
指令(下图)隐士创建后面的类
![](https://img-blog.csdn.net/20180906161359230?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
- 响应式表单
数据模型是由保存在表单中的3个类形成的。模板式表单归根到底也是响应式表单,对响应式表单的封装,由模板中的指令隐士的创建数据模型。
![](https://img-blog.csdn.net/20180906162236718?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
![](https://img-blog.csdn.net/20180906162153879?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
- 响应式表单的重构
指令 区别:formControlName和formControl
formControlName 在使用的时候是这样子 formControlName=‘mobile’ 只能去连接到控制器里面创建的数据模型相对应的对象的key值,是个字符串。
formControl 在使用的时候是这样子 【formControl】=‘mobile’ 它连接的是控制器里面声明的一个属性 。最常见的就是 【formGroup】
![](https://img-blog.csdn.net/20180906162929506?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
下面的【formcontrolnamde】=‘i’,特殊,因为这个数组,数组没有key,循环后声明了一个变量i,这样来搞。
![](https://img-blog.csdn.net/20180906163651314?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
- 响应式表单校验上
什么是angular的校验器
一种是自己定义的,自定义校验器一般都是正确的话返回null,失败的话返回对象,对象的key是校验的规则,在下面响应式表单校验下的模板中显示会用的到
一种angular定义好的。
![](https://img-blog.csdn.net/20180906165516632?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
然后将校验器填到表单模型数据
![](https://img-blog.csdn.net/20180906165705649?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
可以打印错误信息(错误的信息时校验器里面写的)
![](https://img-blog.csdn.net/20180906165910654?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
手机号的校验器
![](https://img-blog.csdn.net/20180906170110349?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
自定义校验器(密码和确认密码)
![](https://img-blog.csdn.net/20180906170340266?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
- 响应式表表单校验下
在模板中显示错误信息
haserror有两个参数第一个是校验器返回的错误对象的key,第二个是检测的name值
![](https://img-blog.csdn.net/20180906171442770?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
另外的一种写法
![](https://img-blog.csdn.net/20180906172558315?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
![](https://img-blog.csdn.net/20180906172628913?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
也可以是异步校验,返回的是一个流
![](https://img-blog.csdn.net/20180906172819637?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
【】第一个是默认值,第二个是同步校验器(只有同步的校验满足了才会执行第三个异步校验),第三个是异步校验器。
![](https://img-blog.csdn.net/20180906172847802?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
表单的状态一般都是vaild和invaild,但是如果有异步校验器的话会多一个pending的状态,表明在调用远程的服务。
- 状态字段(angular4 根据状态字段会生成响应的class类,可以根据类来改变样式)
上面的表单的提示存在的问题是
1.比如用户还没有填呢,就提示这个是必填项,这个就不太友好,状态字段就是为了解决这个问题。每个创建的数据模型都有一下这些属性(字段)
toched = 当前焦点被点过等于true;
untouched = 当前焦点被点过等于false;
pristine = 一个字段的值从未被改变 等于 true;
dirty = 一个字段的值从未被改变 等于 false;
pending = 异步校验true
valid 是否有效
![](https://img-blog.csdn.net/2018090617530725?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
下面这个图和下下面的这个图连起来一起写
![](https://img-blog.csdn.net/2018090617462250?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
![](https://img-blog.csdn.net/20180906174638367?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
一定要按照下面那样写,要不然在jenkins 发布的时候会报错
![](https://img-blog.csdn.net/20180914105623971?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
表单控件的样式
- 模板式表单校验
1.包装成指令(指令就是没有模板的组件)
指令和组件的区别
1.指令没有模板
2.指令的selector 是 属性字符串,用的时候用属性来做,组件是字符串,用的时候用字符串做
指令
![](https://img-blog.csdn.net/20180907072438876?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
指令的使用(作为属性,加【】的话那是子组件的输入属性或者是响应式表单的属性绑定,不要混淆)
![](https://img-blog.csdn.net/20180907075648362?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
组件
![](https://img-blog.csdn.net/20180907072551887?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
组件的使用
![](https://img-blog.csdn.net/20180907072649385?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
自定义的指令校验器(其原理是给这个指令一个提供器,提供器的任务就是校验,下图的tocken 是固定的,所有的模板式表单的指令的校验器都是这个,useValue 后面的电话校验器是一个全局的导出的函数,所以这么写,还得连接下图,加multi,因为这个tocken是共用的,可能会有很多的校验器)
![](https://img-blog.csdn.net/20180907072942480?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
![](https://img-blog.csdn.net/20180907073252365?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
2.用input 的partten来做校验
下图的模板错误信息显示是自己的方法(这样写的做法问题是如果是 多个校验并且需要多个提示那么久麻烦了,比如下图的身份证号是必填项,并且格式要准确,这就提示不准确,到时没填,还没格式不对,如果校验3个更麻烦了,所以复杂的推荐官方的下下图的方法)
![](https://img-blog.csdn.net/20180907081519247?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
这里input 的required 实际上是angular 的指令,不是浏览器 input 本身的require,所以在form 上面写了一个novalid,不然浏览器来做这个校验,而是让angular 去做这个校验(minlength 等等也都是)。
![](https://img-blog.csdn.net/2018090708031355?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
错误时模板的显示(和响应式模板一样,这时候存在的问题是错误的提示信息 一直都存在,需要进行优化)
![](https://img-blog.csdn.net/20180907080709110?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
![](https://img-blog.csdn.net/20180907082439570?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
现在的这种的优化的方式是有问题的,因为模板式表单是同步的,这时候还没有mobile 对象,所以会报错,解决方法如下图
![](https://img-blog.csdn.net/20180907082809554?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
- 实战上(肯定是响应式表单啦)
解决了下拉框或者是checkbox的表单处理(之前用的是操作dom 的方法,及其不合理)
![](https://img-blog.csdn.net/20180907093550969?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
注意,下面的这个多选框在打印的时候会显示true(为勾上)和false(没有勾上),所以new formControll()()里面写boolean ,默认值。表单修改的时候。
![](https://img-blog.csdn.net/20180907093748849?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
解决了下radio 的问题
- 实战下
多选框等的至少选一个的提示
![](https://img-blog.csdn.net/20180907095811732?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
自定义的校验器判断 有没有true就可以
![](https://img-blog.csdn.net/20180907095827971?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
模板错误的提示跟之前一样写
表单不合法时候提交的按钮是禁用的状态, 一定要注意的是一定是dom 属性绑定(看dom 属性绑定一节)disabled 不是disable
![](https://img-blog.csdn.net/20180907100435776?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
以前都是修改当添加的时候也要判断是否有点击过touch和untouch (添加和修改的区别就在于那个fb里面默认值了,其他都是一样的)
动态校验规则(和更深入的理解):比如 联系方式又手机号和邮箱,当选择了手机号才会对手机号进行必填,一开始就直接写必填不行。
https://segmentfault.com/a/1190000010064866#articleHeader7
- 小结
八、与服务器通讯
- 内容介绍
angular 能够跟任何支持http和websocket 协议的服务器进行通讯。
- web服务器
![](https://img-blog.csdn.net/20180907102501180?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
用的是node 的框架expres 搭建的后台服务器
- http通讯
![](https://img-blog.csdn.net/20180907104223976?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
http 通讯应该采用异步的方式,当请求的时候可以做其他的动作 。
方式有:回调函数,es6 的promise等,angular 采用的是响应式编程rxjs实现的。
跨域的处理:
编写 proxy.conf.js
/**
* 配置代理
* @type {[null,null]}
*/
const PROXY_CONFIG = [
{
context: [
"/login" //登录
],
target: test + "8087", //拦截请求路径,转发到test:8087
secure: false
}
];
module.exports = PROXY_CONFIG;
![](https://img-blog.csdn.net/20180907110239946?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
在启动的时候加入代理文件
async 对流数据进行处理的管道:
![](https://img-blog.csdn.net/20180907110702572?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
![](https://img-blog.csdn.net/20180907110735382?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
请求头的添加:
- websocket 通讯(https://git.imooc.com/Project/coding-94/src/master/ch8/client/src/app)
WebSocket是HTML5开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
在WebSocket API中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。
浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP 连接直接交换数据。
当你获取 Web Socket 连接后,你可以通过 send() 方法来向服务器发送数据,并通过 onmessage 事件来接收服务器返回的数据。
以下 API 用于创建 WebSocket 对象。
var Socket = new WebSocket(url, [protocol] );
以上代码中的第一个参数 url, 指定连接的 URL。第二个参数 protocol 是可选的,指定了可接受的子协议
![](https://img-blog.csdn.net/20180908065544407?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
websocket 协议是一种低负载的二进制通讯协议,一些主流的浏览器都支持了websocket协议。
http 协议,数据的传输是单向的,要不请求要不响应,而是是无状态链接,每次链接都需要3次握手
websock协议。数据的传输是双向的,而切是长连接,不是一个请求和响应的协议,客户端和服务器都可以主动发送数据(消息通知,当服务器真正的有数据更新的时候主动推送到客户端,而不是在客户满盲目的定时请求,避免消耗)。
![](https://img-blog.csdn.net/20180908065909860?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
实战
![](https://img-blog.csdn.net/20180908070334848?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
angular 并没有提供像http那样的类,直接在构造函数声明要tocken,所以我们要写一个websocket类(服务)
websocket类(服务) 这个服务两个方法:1. 连接服务器,拿到服务器的消息 2.像服务器发送消息。
![](https://img-blog.csdn.net/20180908073638734?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
- 实战上
npm init -y 就会生成一个pack.json 文件
formModel 重新赋值
- 实战下
- 小结
九、构建和部署
之前所有的工作都是在开发环境完成的,编写代码,然后制定npm run start,来启动一份angular 命令行启动的服务器(比如你可以看到localhost:端口号,就这证明是跑在了一个服务器上面),然后通过浏览器来查看我们的应用。但是我们在实际的正式的环境我们是不可能这么做的的,不可能把源代码都放到生产服务器上面,然后执行npm install,然后安装命令行工具,然后执行npm run start。在正式环境应该使用一个专业的服务器(而不是angular 命令行启动的服务器),比如说是apache 或者是nginx 来处理这些静态的资源(将前台的源代码进行打包编程静态资源)。
将前台的资源打包就是静态资源可以放到服务器上,或者是专业的web 服务器(比如nginx)
![](https://img-blog.csdn.net/20180908081507748?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
1.构建:编译和合并(其实内部是由webpack 来做这个事情的,命令行工具集成了webpack)
编译:我们的应用是用 typescript 编写的,在浏览器里面运行 这些 代码需要将ts 变异成js,虽然ts 提供了一个编译器,可以实时的将ts变为js 在浏览器中运行(在项目中有一个tsconfig.json 的文件,就是 用来把ts 翻译成 js 的)。 但是在生产环境这样做的话会有两个问题。第一:浏览器需要额外的加载ts 的编译器,这个编译器有几百k,第二:每次执行代码前都要进行编译。这两个问题会导致我们的应用的性能下降。所以在部署到服务器之前,我们要在线下编成js。
合并:很多的js 等,每个都请求一遍,服务器会受不了。为了减少服务器的压力,将进行合并。这样只需要发几个请求就能够拿到很多的东西。(可以看到合并 后的js文件只有6个,当然还有其他的文件,比如index.html 和图片字体等)
![](https://img-blog.csdn.net/20180908085044838?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
![](https://img-blog.csdn.net/20180908172854516?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
如果用ng build --prod 来编译,代码里成上述文件,打包出来的会优化不少
编译aot (预编译) 和 jit(即使编译) 默认是及时编译,快。aot 小。aot 也可以帮我们进行类型检查等,进行排错。
ng build --prod 默认是aot 编译, 启用生产环境
一句话概括就是 启动时候写 ng build --prod https://www.angular.cn/guide/deployment
![](https://img-blog.csdn.net/20180908173702716?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
2. 部署:与服务器进行整合。
最简单的方式就是把打包后的静态资源手动复制到服务器里面(后台代码可以处理静态资源,比如下面的nodejs 处理静态资源)
![](https://img-blog.csdn.net/20180908085749106?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
复杂一点的话可以用一些自动化的构建工具。
3.多环境(页面上有些东西希望在不同的环境显示不同的,比如 开发环境写 开发环境,生产环境写生产环境)
![](https://img-blog.csdn.net/20180908090143568?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
![](https://img-blog.csdn.net/20180908135945282?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dpdGh1Yl8zOTMxOTAwMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
十、课程总结
- 总结