一、搭建Angular开发环境
安装nodejs, Angular Cli, WebStorm
先安装nodejs, 安装完成后用命令来安装Angular Cli
npm install -g @angular/cli
使用Angular Cli创建并运行Angular项目
用ng new 命令来创建一个项目,比如项目名为demo,则输入命令 ng new demo
分析Angular目录结构及Angular Cli 生成的基础代码
e2e 端到端的测试目录,用来做自动测试的
node_modules 第三方的依赖包
src 源代码目录
app 包含应用的组件和模块
assets 用来存放静态资源文件
environment 环境配置,支持多环境开发,比如开发环境和生产环境可以共用一套代码
index.html 整个应用的根文件
main.ts 整个应用的入口点
polyfills.ts 导入必要的库,使angular可以正常运行在老版本的浏览器
style.css 应用的全局样式
test.ts 做自动化测试的
tsconfig.json ts的配置文件
.editconfig webStorm的配置文件
.gitignore git的配置文件
angular-cli.json angular命令行工具的配置文件
karma.config.js karma的配置文件,用来执行自动化测试的
package.json 标准的npm工具的配置文件,当前应用使用的第三方工具包,通过npm i 来安装
protractor.conf.js 跟karma类似,也是用来做自动化测试
tslint.json 用来定义ts代码的质量检查
二、组件
定义:在angular中组件就是一个ts类,然后通过@Component装饰器装饰,装饰器里面定义了组件的元数据,包括样式,模板等等。
组件要素
必备
装饰器、模板和控制器
可选
输入属性@Input---父组件向子组件传递数据
提供器 providers---用来做依赖注入
生命周期钩子
样式表
动画---angular 提供动画包帮助我们创建组件间的动画效果
输出属性---用来在组件间共享数据
模块
用@NgModule装饰器装饰的一个ts类
元数据
declarations 只能声明组件,指令和管道
imports 引用app模块需要依赖的模块
providers 用来声明模块中提供什么服务,只能声明服务
bootstrap 声明模块的主组件
三、Angular路由
Routes
路由配置,保存着哪个URL对应展示哪个组件,以及在哪个RouterOutlet中展示
RouterOutlet
在HTML中标记路由内容呈现位置的占位符指令
Router
路由的对象,用来跳转路由,在控制器使用
RouterLink
在HTML中声明路由导航用的指令,根路由要用‘/’开头,参数是一个数组。.比如 <a [routerLink]="['/']"></a>
ActivatedRoute
当前激活的路由对象,保存着路由信息。
在路由中传递参数的三种方式:
1、在查询参数中传递
/product?id=1&name=2 => ActivatedRoute.queryParams[id]
2、在路由路径中传递参数
{path:'product/:id'} => /product/1 => ActivatedRoute.params[id]
3、在路由配置中传递参数
{path:'product', data:[{isProd:true}]} => ActivatedRoute.data[0][isProd]
参数订阅和参数快照snapshot
如果不会出现组件路由到自身的情况,则可使用参数快照来获取参数。如果会出现路由到自身的情况,则用参数订阅,也就是subcribe()方法。
为什么要这样做?
这是因为,当组件路由到自身的时候,由于组件已经被创建,那么就不会再执行ngOninit方法。而通过订阅则可以解决这个问题。
重定向路由
在用户访问特定的地址时,将其重定向到其他的地址
可用redirectTo属性
子路由
路由间的父子关系,可以无限嵌套
在用RouterLink指令时,路由要用'./'开头,表示从当前路由开始
辅助路由
路由守卫
当用户满足某种条件后才允许用户进入或离开路由。
CanActivate: 处理导航到路由的情况
CanDeActivate: 处理从当前路由离开的情况
Resolve: 在路由激活之前获取路由数据
实现:需要创建一个ts类,该类继承对应的守卫类,实现对应的方法。然后在Routes里面加入对应的属性,再把创建的类添加到providers里面。
四、依赖注入
依赖注入解决的问题
当一个方法或者类依赖其他类时,使用前需要先实例化其他类。当依赖的类多了,要实例化所有的类也是一件麻烦的事。那么能不能把实例化的工作交给其他人做, 我们只需要知道依赖哪些类,而不需要知道具体的实例方法。
依赖注入DI 和 控制反转IOC
依赖注入:侧重于描述手段,如何来实现控制反转的手段
控制反转:侧重于描述目的,即依赖的控制权由代码的内部转移到代码的外部
使用依赖注入的好处
1、松耦合、可重用性
2、提高可测试性
angular如何实现
注入器 在构造函数中声明需要用到的类
constructor(private productService: ProductService){}
提供器 在模块或组件的providers属性声明provider
providers:[ProductService]
providers:[provider:ProductService, useClass: ProductService]
providers:[provider:ProductService, useClass: AnotherProductService]
provider指定了提供器的token,跟构造器中声明的类对应。
useClass指定了具体实例化的类
providers:[provider:ProductService, useFactory: () => {...}] 工厂提供器
根据某些条件决定具体实例化哪些对象,也有可能在实例化对象时需要传入参数,这时就需要用到工厂提供器
在使用工厂方法时,如果需要依赖其他类,则需要用到第三个参数deps:[],在deps的数组中传入需要依赖的类,然后在useFactory的参数中传递进去。
providers:[provider:"APP_CONFIG", useValue: {isDev:false}]
useValue可以传值,也可以传对象
作用域规则
1、声明在模块时,对所有组件可用
2、当提供器声明在组件时,只对组件和其子组件可用
3、当声明在模块和组件具有相同的token时,组件中的提供器会覆盖模块中的提供器
4、优先将服务提供器声明在组件,只有该提供器对其他组件不可用时才声明在组件中
注入器的层级关系
应用级注入器 > 主组件注入器 > 子组件注入器
五、组件间通讯
组件的输入输出属性
输入属性:用@Input()装饰器注解的属性,属性绑定是单项的
输出属性: 用@Output()装饰器注解的属性 ,需要用到EventEmitter。从angular/core引入
声明: lastPrice: EventEmitter<PriceQuote> = new EventEmitter();
可以通过emit(value)方法把值发射出去,父组件就可以通过子组件的事件绑定接收到数据。
使用中间人模式传递数据
中间人模式:如果组件A和组件B要进行通信,他们有共同的父组件,则可以把父组件当中间人,A组件把值发射给父组件,父组件接收后把值通过B组件的Input属性传递给B组件。
如果两个组件没有共同的父组件,则可以通过服务来订阅事件。
组件生命周期及angular的变化发现机制
左边的是组件初始化调用的事件,红色的事件只调用一次,绿色的事件会被多次调用。如果组件有输入属性,则组件在被初始化时会调用ngOnChanges事件。由于这个事件是在构造器之后调用,所以不能在构造函数做初始赋值操作,最好是在ngOnInit方法中做初始化操作。
ngOnChanges什么情况下会被调用
1、必须是输入属性发生改变
2、输入属性的地址发生改变,如果输入属性是引用类型,改变该变量的属性值是不会触发ngOnChanges事件
变更检测和DoCheck钩子
变更检测是通过zone.js来实现的
事件会触发变更检测机制,变更检测机制被触发就会调用DoCheck钩子。
如果钩子上有check的钩子,当触发变更检测机制,所有带check的钩子都会被调用,所以在使用带check的钩子要非常小心。
@ViewChild装饰器
可以让父组件获取子组件的引用,调用子组件的方法。
ngAfterViewInit和ngAfterViewChecked
这两个方法都是在组件的视图被组装完毕才调用
如果组件有子组件,只有当所有子组件的视图都被组装完成后,父组件才会被调用
不要在这两个方法中去改变视图中绑定的东西,如果想改变,要写在定时器里面,不然会抛出异常。
ng-content标签可以把父组件模板中任意的片段投影到子组件中去。
ngAfterContentInit和ngAfterContentChecked
在被投影进来的内容组装完被调用
ngOnDestroy
在切换路由的时候调用
在这个钩子反订阅一个流或者清除定时器
六、表单处理
模板式表单
表单的数据模型通过组件模板中的相关指令来定义的,会受限于HTML的语法,所以,模板式表单只适合用于一些简单的场景。
NgForm -> FormGroup
angular会自动为form表单添加ngForm指令,如果不想让它接管,可以在form表单添加ngNoForm指令
ngForm可以在form之外使用,比如在div中添加
ngForm可以被模板本地变量引用
NgModule -> FormControl
NgModuleGroup -> FormGroup
响应式表单
在组件的控制器中创建一个底层的数据模型,然后使用一些特定的指令,将模板上的HTML元素与数据模型连接起来。
FormControl
FormGroup
FormArray
可以增长的自动集合
五个指令
formControl
formControlName
formGroup
formGroupName
formArrayName
指令中后面有name的不能使用属性绑定语法,也就是不能加[]
当formControl和formGroup在一个嵌套里面,则需要加name
FormBuilder便捷创建数据模型
表单验证
angular的校验器
内置校验器:Validator
常用的有required, minlength
自定义校验器
校验器名(control:FormControl): any{ return null; }
异步校验器 返回的是一个可观测的流
校验响应式表单
判断模板式表单是否有错误,可以用hasError方法。第一个参数是校验器名,第二个参数是校验的属性。如果是嵌套的属性,则传递一个数组,第一个值是一级属性,第二个值是二级属性。
getError方法可以获取到具体的报错信息
校验模板式表单
需要把自定义的校验方法封装为指令,才能在模板中调用
表单状态字段
touched和untouched 判断字段是否获取过焦点,用来控制错误信息是否显示
pristine和dirty 判断字段的值是否修改过
pending