Angular学习笔记
一:学习记录
3, @viewchild()修饰器相关:
@ViewChild('myname'/ Component, {read: ViewContainerRef, static: true}) target : targetType;
4, 动态组件:https://segmentfault.com/a/1190000011800979
5, 双向绑定
- 自定义组件双向绑定最“简单”, 使用x和xChange事件, 即[(x)],原生的HTML元素不支持此类用法
- 原生的HTML元素分为两类,一类是表单,可以直接使用[(ngModel)],框架会自动双向绑定【原因是Angular为所有的原生表单都提供了“值访问器”】,另一类是其他原生HTML元素,angular框架没有实现“值访问器”,而且不能使用x和xChange事件,所以如果想要双向绑定,只能使用[(ngModel)]然后自己实现值访问器。
6,
二:问题记录
7, 自己写的两个模块,其中一个要用到第二个中的一些组件,如何写? exports数组
8,单例应用?中的forRoot方法?
平时记录:
※, ng generate component list --prefix separate-setting ;
※,升级 angular 并引入 ng-zorro 框架
0. npm view @angular/core version(s) 查看 @angular/core 的最新可用(所有可用)版本
1. 手动改package.json中的 @angular/core,等相关依赖的版本,ng-zorra官网 可以查看 ng-zorra框架对应的angular版本号
2. npm install 安装依赖
3. ng add ng-zorro-antd 安装ng-zorra框架,可以指定版本号 ng add ng-zorra-antd@x.x.x
4. npm start 哪里报错改哪里(一般错误是某些依赖版本不对,按照改成相应版本然后npm install 即可)
※,
NG-ZORRO官网: https://ng.ant.design/docs/introduce/zh
NG-ZORRA国内镜像:https://ng-zorro.gitee.io/docs/introduce/zh
官网学习笔记
一,组件与模板
1, 显示数据
- 1, 组件的概念:一个带有
@Component()
装饰器的类,和它的伴生模板关联在一起。组件类及其模板共同定义了一个视图。组件是指令的一种特例。@Component()
装饰器扩展了@Directive()
装饰器,增加了一些与模板有关的特性。Angular 的组件类负责暴露数据,并通过数据绑定机制来处理绝大多数视图的显示和用户交互逻辑。 - 1,可以使用指令来向模板中添加逻辑,指令告诉 Angular 在渲染页面时要如何修改。
- 1,要显示组件的属性,最简单的方式就是通过插值 (interpolation) 来绑定属性名。 要使用插值,就把属性名包裹在双花括号里放进视图模板,如
{{myHero}}
。 - 1, *ngFor="let hero of heroes" 中的 hero 叫做 模板输入变量
- 1 可以通过组件和指令来扩展模板中的 HTML 词汇。它们看上去就是新元素和属性。
2 模板语法:
- 插值:插值是一种特殊语法,Angular 会将其转换为属性绑定。如果你想用别的分隔符来代替
{{
和}}
,也可以通过Component
元数据中的 interpolation 选项来配置插值分隔符。 - 模板表达式 (点此):
- {{1+2}}中的1+2, 以及属性绑定 [attr]="1+2"等号右侧的1+2 叫做模板表达式。
- 模板表达式类似JavaScript代码,但是不能使用那些具有或可能引发副作用的 JavaScript 表达式(如赋值,new, 表达式链(;)等),也不能引用全局命名空间中的任何东西,比如
window
或document
。它们也不能调用console.log
或Math.max
。 它们只能引用模板表达式上下文中的成员。假如该表达式调用了具有副作用的属性或方法,比如调用类似getFoo()
的函数,只有你知道getFoo()
做了什么。如果getFoo()
更改了某些内容,而你恰巧绑定到该内容,则 Angular 可能会也可能不会显示更改后的值。Angular 可能会检测到更改并抛出警告错误。最佳实践是坚持使用属性和返回值并避免副作用的方法。
- 表达式上下文:典型的表达式上下文就是这个组件实例,它是各种绑定值的来源。表达式中的上下文变量是由模板变量(1,模板输入变量;2,模板引用变量)、指令的上下文变量(如果有)和组件的成员叠加而成的。 如果你要引用的变量名存在于一个以上的命名空间中,那么,模板变量是最优先的,其次是指令的上下文变量,最后是组件的成员。
- 模板表达式使用指南:
- 属性名或方法调用应该是常态,但偶然使用逻辑取反
!
也是可以的。 其它情况下,应该把应用程序和业务逻辑限制在组件中,这样它才能更容易开发和测试。 -
模板表达式除了目标属性的值以外,不应该改变应用的任何状态。这条规则是 Angular “单向数据流”策略的基础。 永远不用担心读取组件值可能改变另外的显示值。 在一次单独的渲染过程中,视图应该总是稳定的。
- 属性名或方法调用应该是常态,但偶然使用逻辑取反
- 模板语句(点此):1 模板语句用来响应由绑定目标(如 HTML 元素、组件或指令)触发的事件。 模板语句将在事件绑定一节看到,它出现在
=
号右侧的引号中,就像这样:(event)="statement"
。2 和模板表达式一样,模板语句使用的语言也像 JavaScript。 模板语句解析器和模板表达式解析器有所不同,特别之处在于它支持基本赋值 (=
) 和表达式链 (;
)。3 和表达式中一样,语句只能引用模板语句上下文中 —— 通常是正在绑定事件的那个组件实例。 - 模板语句上下文:典型的语句上下文就是当前组件的实例。语句上下文可以引用模板上下文中的属性,如模板的$event对象,模板输入变量,模板引用变量<form #heroForm (ngSubmit)="onSubmit(heroForm)"> ... </form>
- 模板语句使用指南:
-
模板语句不能引用全局命名空间的任何东西。比如不能引用
window
或document
,也不能调用console.log
或Math.max
。和表达式一样,避免写复杂的模板语句。 常规是函数调用或者属性赋值。
-
- 数据绑定:
- 组件--->模板
- 插值,属性(property),Attribute, CSS 类,样式;
-
{{expression}}
[target]="expression"
bind-target="expression"
- 模板---->组件
- 事件
-
(target)="statement"
on-target="statement"
- 模板<---->组件
-
[(target)]="expression"
bindon-target="expression"
-
- 数据绑定的通用规则。数据绑定使用 DOM 元素、组件和指令的 Property,而不是 HTML 的Attribute 。
-
HTML attribute 与 DOM property 的对比。该通用规则可以帮助你建立 HTML Attribute 和 DOM Property 的思维模型: attribute 负责初始化 DOM property,然后完工。Property 值可以改变;Attribute 值则不能。
- property 绑定: [target]="expression"
- 方括号
[]
告诉 Angular 计算该模板表达式。如果省略括号,Angular 会将字符串视为常量,并使用该字符串初始化目标属性(property)。但有时候可以特意使用这种方式。 - 属性property绑定和插值表达式 在属性值为字符串的情况下是可以通用的,如下面是等效的。但是属性值不为字符串时必须使用属性property绑定。
<p><img src="{{itemImageUrl}}"> is the <i>interpolated</i> image.</p>
<p><img [src]="itemImageUrl"> is the <i>property bound</i> image.</p><p><span>"{{interpolationTitle}}" is the <i>interpolated</i> title.</span></p>
<p>"<span [innerHTML]="propertyTitle"></span>" is the <i>property bound</i> title.</p> - 属性绑定会过滤<script>标签,插值表达式会原样显示<script>标签
- 方括号
- attribute、class、style 绑定:模板语法为那些不太适合使用属性绑定的场景提供了专门的单向数据绑定形式。
-
attribute绑定:通常,使用 Property 绑定设置元素的 Property 优于使用字符串设置 Attribute。但是,有时没有要绑定的元素的 Property,所以其解决方案就是 Attribute 绑定。
<!-- create and set an aria attribute for assistive technology -->
<button [attr.aria-label]="actionName">{{actionName}} with Aria</button> - 注意
colspan
Attribute 和colSpan
Property 之间的区别。插值和 Property 绑定只能设置 Property,不能设置 Attribute。所以这么写是错误的:<tr><td colspan="{{1 + 1}}">Three-Four</td></tr>,应该这么写:<!-- Notice the colSpan property is camel case -->
<tr><td [colSpan]="1 + 1">Three-Four</td></tr> - 类绑定:
- 单个类绑定: [class.foo]="boolean | undefined | null"
- 多个类绑定: [class]="classExpr",classExpr可以为以下:
- string, 如,"my-class-1 my-class-2 my-class-3",注意写法:[class]="'class1 class2 class3'",即需提供字符串,用引号引起来
- {[key: string]: boolean | undefined | null}, 如{foo: true, bar: false}
Array
<string
>,如,['foo', 'bar']
- 尽管此技术适用于切换单个类名,但在需要同时管理多个类名时请考虑使用
NgClass
指令。
- style绑定:
- 单一样式绑定:[style.width]="string | undefined | null",如:[style.width]="'100px'",注意用引号把100px引起来才是正确的写法。
- 带单位的单一样式绑定:[style.width.px]="number | undefined | null",如[style.width]="100"
-
多个样式绑定:[style]="styleExpr", styleExpr可以为下:
- string:"width: 100px; height: 100px"
- {[key: string]: string | undefined | null}:
Array
<string
>:
-
NgStyle 指令可以作为
[style]
绑定的替代指令。但是,应该把上面这种[style]
样式绑定语法作为首选,因为随着 Angular 中样式绑定的改进,NgStyle
将不再提供重要的价值,并最终在未来的某个版本中删除。
- 样式绑定和类绑定的优先级规则
-
委托优先级较低的样式: 更高优先级的样式可以使用
undefined
值“委托”给低级的优先级样式。虽然把 style 属性设置为null
可以确保该样式被移除,但把它设置为undefined
会导致 Angular 回退到该样式的次高优先级。
-
-
事件绑定
- 双向绑定 [(...)]
- <app-sizer [(size)]="fontSizePx"></app-sizer>;子组件app-sizer中要有两个属性: @Input() size: number | string; @Output() sizeChange = new EventEmitter<number>();
- 双向绑定语法实际上是属性绑定和事件绑定的语法糖。 Angular 将
SizerComponent
的绑定分解成这样:<app-sizer [size]="fontSizePx" (sizeChange)="fontSizePx=$event"></app-sizer> - 表单中的双向绑定
-
NgModel 和值访问器: [https://angular.cn/guide/template-syntax#ngmodel-and-value-accessors]
-
NgModel
指令仅适用于通过 ControlValueAccessor 适配过这种协议的元素。Angular 已经为所有基本的 HTML 表单元素提供了值访问器 - 在编写适当的值访问器之前,不能将
[(ngModel)]
应用于非表单的原生元素或第三方自定义组件。欲知详情,参见DefaultValueAccessor上的 API 文档。 - 你不一定非用为所编写的 Angular 组件提供值访问器,因为你还可以把值属性和事件属性命名为符合 Angular 的基本双向绑定语法的形式,并完全跳过
NgModel
。 - 见下面其他说明
-
- 内置指令:Angular 提供了两种内置指令:属性型指令和结构型指令
-
内置属性型指令:属性型指令会监听并修改 HTML 元素和组件的行为、Attribute 和 Property。常见的属性型指令有
NgClass
—— 添加和删除一组 CSS 类。(感觉和类绑定 [class]="classExpr"差不多,具体有待探究)NgStyle
—— 添加和删除一组 HTML 样式。(同上,类似样式绑定[style]="styleExpr")NgModel
—— 将数据双向绑定添加到 HTML 表单元素。要想在双向数据绑定中使用ngModel
指令,必须先导入FormsModule
并将其添加到 NgModule 的imports
列表中。- <input [(ngModel)]="propVal" />,拆成如下:
- <input [ngModel]="propVal" (ngModelChange)="propVal=$event" />, 背后的逻辑是这样的:<input [value]="propVal" (input)="propVal=$event.target.value" />
[(ngModel)]
语法只能设置数据绑定属性。如果你要做得更多,可以编写扩展表单。例如,下面的代码将<input>
值更改为大写:- <input [ngModel]="currentItem.name" (ngModelChange)="setUppercaseName($event)" id="example-uppercase">
- 内置结构型指令:结构型指令的职责是 HTML 布局。常见的结构型指令有:
NgIf
—— 从模板中创建或销毁子视图。NgFor
—— 为列表中的每个条目重复渲染一个节点。- 赋值给
*ngFor
的字符串不是模板表达式。而是一个微语法 —— 由 Angular 解释的一种小型语言。字符串"let item of items"
的意思是:将items
数组中的每个条目存储在局部循环变量item
中,并使其可用于每次迭代的模板 HTML 中。Angular 将该指令转换为包裹着宿主元素的<ng-template>
,然后反复使用此模板为列表中的每个item
创建一组新的元素和绑定。 item
前面的let
关键字创建了一个名为item
的模板输入变量。- *ngFor="let item of items; let i=index; let fir=first;let o=odd;let e=even;let cnt=count",其中的index,first等值可以被捕获并使用
- 赋值给
NgSwitch
—— 一组在备用视图之间切换的指令。NgSwitch
实际上是三个协作指令的集合:NgSwitch
,NgSwitchCase
和NgSwitchDefault
-
<div [ngSwitch]="currentItem.feature">
<app-stout-item *ngSwitchCase="'stout'" [item]="currentItem"></app-stout-item>
<app-device-item *ngSwitchCase="'slim'" [item]="currentItem"></app-device-item>
<app-lost-item *ngSwitchCase="'vintage'" [item]="currentItem"></app-lost-item>
<app-best-item *ngSwitchCase="'bright'" [item]="currentItem"></app-best-item>
<!-- . . . -->
<app-unknown-item *ngSwitchDefault [item]="currentItem"></app-unknown-item>
</div> - 如果试图写成
*ngSwitch
,就会出现错误,因为NgSwitch
是属性型指令,而不是结构型指令。它不会直接接触 DOM,而是会更改与之相伴的指令的行为。 NgSwitchCase
和NgSwitchDefault
指令都是结构型指令,因为它们会从 DOM 中添加或移除元素。
- 当指令没有合适的宿主元素时,使用
<ng-container>
对元素进行分组。你只能往一个元素上应用一个结构型指令。 -
模板引用变量(
#var
):模板引用变量通常是对模板中 DOM 元素的引用。它还可以引用指令(包含组件)、元素、TemplateRef 或 Web Component。- 使用井号(#)声明模板引用变量,可以在组件模板中的任何位置引用模板引用变量。
- 在大多数情况下,Angular 会将模板引用变量的值设置为声明该变量的元素。
NgForm
指令可以更改该行为并将该值设置为其它值。 -
<form #itemForm="ngForm" (ngSubmit)="onSubmit(itemForm)">
<label for="name"
>Name <input class="form-control" name="name" ngModel required />
</label>
<button type="submit">Submit</button>
</form><div [hidden]="!itemForm.form.valid">
<p>{{ submitMessage }}</p>
</div> - 带有
NgForm
时,itemForm
就是对 NgForm 指令的引用,它能够跟踪表单中每个控件的值和有效性。原生<form>
元素没有form
属性,但NgForm
指令有,这样就能在itemForm.form.valid
无效的情况下禁用提交按钮,并将整个表单控制树传给父组件的onSubmit()
方法。 - 模板引用变量的范围是整个模板。因此,不要在同一模板中多次定义相同的变量名,因为它在运行时的值将不可预测。
- 也可以用
ref-
前缀代替#。
<input ref-fax placeholder="fax number" />
<button (click)="callFax(fax.value)">Fax</button>
-
- 组件--->模板
- 输入输出属性
@Input()
和@Output()
- 要监视
@Input()
属性的更改,请使用 Angular 的生命周期钩子之一OnChanges
。OnChanges
是专门设计用于具有@Input()
装饰器的属性的。欲知详情,请参见生命周期钩子指南的OnChanges
部分。 - 可以在组件或指令的元数据的
inputs
和outputs
数组中标出这些成员,而不是使用@Input()
和@Output()
装饰器来声明输入和输出,但是风格指南中建议使用装饰器 - 指定别名:
- 要在元数据中为输入和输出指定别名,请使用冒号分隔(
:
)的字符串,其左边是属性名,右边是别名: - inputs: ['input1: saveForLaterItem'], // propertyName:alias outputs: ['outputEvent1: saveForLaterEvent']
- 你可以通过将别名传给
@Input()
/@Output()
装饰器来为属性名指定别名。其内部名称保持不变(对内和对外分别使用本名和别名)。 -
@Input('wishListItem') input2: string; // @Input(alias)
@Output('wishEvent') outputEvent2 = new EventEmitter<string>(); // @Output(alias) propertyName = ... - 当为@Input()属性设置get/set方法时,用法如下:
- @Input() set hero(hero:Hero){this._hero = hero;} 这会在父组件将值传入子组件时调用此set方法。
- 要在元数据中为输入和输出指定别名,请使用冒号分隔(
- 要监视
-
模板表达式中的运算符:Angular 模板表达式的语言是 JavaScript 语法的子集,并为特定情况添加了一些特殊的运算符。接下来将介绍其中的三个运算符:
- 内置模板函数:
- 类型转换函数:使用
$any()
转换函数来把表达式转换成any
类型. - <p>The item's undeclared best by date is: {{$any(item).bestByDate}}</p>
- <p>The item's undeclared best by date is: {{$any(this).bestByDate}}</p>
- 类型转换函数:使用
-
模板中的SVG:可以将 SVG 用作 Angular 中的有效模板。在 SVG 1.1和2.0 规范中了解更多信息。为什么要用 SVG 作为模板,而不是简单地将其作为图像添加到应用程序中?当你使用 SVG 作为模板时,就可以像 HTML 模板一样使用指令和绑定。这意味着你将能够动态生成交互式图形。
3, 用户输入
- 反对把整个 DOM 事件(即$event对象)传到方法中,因为这样组件会知道太多模板的信息。 只有当它知道更多它本不应了解的 HTML 实现细节时,它才能提取信息。 这就违反了模板(用户看到的)和组件(应用如何处理用户数据)之间的分离关注原则。
- 建议使用模板引用变量获取用户输入:<input #box (keyup)="0"> <p>{{box.value}}</p>。除非你绑定一个事件,否则这将完全无法工作。只有在应用做了些异步事件(如击键),Angular 才更新绑定(并最终影响到屏幕)。 本例代码将
keyup
事件绑定到了数字 0,这可能是最短的模板语句了。 虽然这个语句不做什么,但它满足 Angular 的要求,所以 Angular 将更新屏幕。 - 监听特定按键: 1,$event.keyCode==13 ; 2, <input #box (keyup.enter)="onEnter(box.value)">; keyup.任意键都可以
- Angular 还支持被动事件侦听器。
4,属性型指令:属性型指令用于改变一个 DOM 元素的外观或行为。
- 在 Angular 中有三种类型的指令:
-
组件 — 拥有模板的指令
-
结构型指令 — 通过添加和移除 DOM 元素改变 DOM 布局的指令
-
属性型指令 — 改变元素、组件或其它指令的外观和行为的指令。如,NgClass, NgStyle, NgModel
- @Directive({ selector: '[appHighlight]' }), 注意selector 的值是用方括号包起来的,普通的模板selector并不需要。
- angular绑定机制的信任度问题 : 从angular的绑定机制看,组件或指令的属性是私有的,只能被属于它的模板绑定;而当添加了
@Input
时,Angular 绑定机制才会把它们当成公共的。 只有这样,它们才能被其它组件或属性绑定。注意理解以下:<p [appHighlight]='color'>xxxx</p>中的 APPHighlight 和 color 都是当前模板中绑定的属性,但是color是属于相互信任的当前组件中的属性所以不用加@Input(),但是AppHighlight 则对于当前模板来说是属于其他组件或指令的属性,不能互相信任,所以这个其他的组件或指令就需要添加@Input()修饰,将其变成绑定机制中的公共的属性。
5,结构型指令:三个常用的内置结构型指令 —— NgIf、NgFor和NgSwitch...。NgIf
引用的是指令的类名,而 ngIf
引用的是指令的属性名。
*ngIf:
- <div *ngIf="hero" class="name">{{hero.name}}</div>
- 星号是一个用来简化更复杂语法的“语法糖”。 从内部实现来说,Angular 把
*ngIf
属性 翻译成一个<ng-template>
元素 并用它来包裹宿主元素,代码如下: -
<ng-template [ngIf]="hero">
<div class="name">{{hero.name}}</div>
</ng-template> - Angular 会在真正渲染的时候填充
<ng-template>
包裹的内容,并且把<ng-template>
替换为一个供诊断用的注释。
*ngFor
- Angular 会把
*ngFor
用同样的方式把星号(*
)语法的template
属性转换成<ng-template>
元素。 -
<div *ngFor="let hero of heroes; let i=index; let odd=odd; trackBy: trackById" [class.odd]="odd">
({{i}}) {{hero.name}}
</div><ng-template ngFor let-hero [ngForOf]="heroes" let-i="index" let-odd="odd" [ngForTrackBy]="trackById">
<div [class.odd]="odd">({{i}}) {{hero.name}}</div>
</ng-template>
-
星号(
*
)语法比不带语法糖的形式更加清晰。 如果找不到单一的元素来应用该指令,可以使用<ng-container>作为该指令的容器。虽然很少有理由在模板中使用结构型指令的属性形式和元素形式,但这些幕后知识仍然是很重要的,即:Angular 会创建
<ng-template>
,还要了解它的工作原理。 当需要写自己的结构型指令时,你就要使用<ng-template>
。
每个宿主元素上只能有一个结构型指令:
- 原因很简单。结构型指令可能会对宿主元素及其子元素做很复杂的事。当两个指令放在同一个元素上时,谁先谁后?
NgIf
优先还是NgFor
优先?NgIf
可以取消NgFor
的效果吗? 如果要这样做,Angular 应该如何把这种能力泛化,以取消其它结构型指令的效果呢? - 对这些问题,没有办法简单回答。而禁止多个结构型指令则可以简单地解决这个问题。 这种情况下有一个简单的解决方案:把
*ngIf
放在一个"容器"元素上,再包装进*ngFor
元素。 这个元素可以使用ng-container
,以免引入一个新的 HTML 层级。
<ng-template>元素:
- <ng-template>是一个 Angular 元素,用来渲染 HTML。 它永远不会直接显示出来。 事实上,在渲染视图之前,Angular 会把
<ng-template>
及其内容替换为一个注释。 - 如果没有使用结构型指令,而仅仅把一些别的元素包装进
<ng-template>
中,那些元素就是不可见的。结构型指令会让<ng-template>
正常工作。 TemplateRef
取得<ng-template>
的内容
<ng-container>元素:
- Angular 的
<ng-container>
是一个分组元素,但它不会污染样式或元素布局,因为 Angular 压根不会把它放进 DOM 中。 - 有些 HTML 元素需要所有的直属下级都具有特定的类型。 比如,
<select>
元素要求直属下级必须为<option>
,当需要使用结构型指令时,就没办法把这些选项<option>包装进<div>
或<span>
中,此事就可以使用 ng-container。当然ng-container还有其他很多使用场景。 <ng-container>
是一个由 Angular 解析器负责识别处理的语法元素。 它不是一个指令、组件、类或接口,更像是 JavaScript 中if
块中的花括号。
6,管道:管道是一些简单的函数,可以在模板表达式中用来接受输入值并返回一个转换后的值。
- Angular 为典型的数据转换提供了内置的管道。请参阅管道 API 文档 。
- 如果管道能接受多个参数,就用冒号分隔这些值。{{ amount | currency:'EUR':'Euros '}}
- 自定义管道的一个例子:
- test.pipe.ts
import {Pipe, PipeTransform} from '@angular/core'; @Pipe({ name: 'test', /** * pure属性默认为true,代表其实纯管道,pure的意思是angular检测管道值变化以决定是否需要重新渲染时只检测pure变更, * 所谓pure变更即是 基本类型的变更 或者 对象引用的变更,而对象引用不变时,对象中的成员发生变化不属于pure变更, * 只有将pure属性设置为false时才会检测对象成员的变更进而重新渲染。虽然非纯管道很实用,但要小心使用。长时间运行非纯管道可能会大大降低你的应用速度。 */ // pure:false }) // 管道也可以继承 export class TestPipe implements PipeTransform { /** * 管道必须实现 PipeTransform 接口,transform第一个参数是管道前的输入, * 管道的参数被收集在args变量中。 */ transform(value: any, ...args:any[]): unknown { let retval = "ThisIsTestPipe,输入:" + value ; if (args.length > 0) { retval += ",参数:" for (let [index, arg] of args.entries()) { retval += String(arg); if (index != args.length - 1) { retval += ","; } } } return retval; } }
- html 模板使用此管道
<!--fontSizePx是组件属性,管道会检测其变化而重新渲染--> <div>{{'测试自定义管道'|test:"参数1":"参数2":null:undefined:3:true:{key:"value"}:fontSizePx }}</div>
-
AsyncPipe : 使用内置的
AsyncPipe
接受一个可观察对象作为输入,并自动订阅输入。如果没有这个管道,你的组件代码就必须订阅这个可观察对象来使用它的值,提取已解析的值、把它们公开进行绑定,并在销毁这段可观察对象时取消订阅,以防止内存泄漏。AsyncPipe
是一个非纯管道,可以节省组件中的样板代码,以维护订阅,并在数据到达时持续从该可观察对象中提供值。 - <p>Message: {{ message$ | async }}</p>, message$是组件中的一个属性名称,使用$结尾不是语法,只是一个约定,表示这个变量是个可观察对象。
7, 生命周期钩子:
- 你可以通过实现一个或多个 Angular
core
库中定义的生命周期钩子接口来响应组件或指令生命周期中的事件。这些钩子让你有机会在适当的时候对组件或指令实例进行操作,比如 Angular 创建、更新或销毁这个实例时。每个接口都有唯一的一个钩子方法,它们的名字是由接口名再加上ng
前缀构成的。比如,OnInit
接口的钩子方法叫做ngOnInit()
。如果你在组件或指令类中实现了这个方法,Angular 就会在首次检查完组件或指令的输入属性后,紧接着调用它。 - ngOnChanges() 检测@Input()修饰的属性变化时,同时在
ngOnInit()
之前也会检测一次。 -
ngOnChanges(changes: SimpleChanges) { for (let propName in changes) { let chng = changes[propName]; let cur = JSON.stringify(chng.currentValue); let prev = JSON.stringify(chng.previousValue); this.changeLog.push(`${propName}: currentValue = ${cur}, previousValue = ${prev}`); } }
或者: ngOnChanges(changes: {[propKey: string]: SimpleChange}) {} - 检测投影内容的变更:
AfterContentInit()
和AfterContentChecked()
钩子 - 自定义变更检测:
ngDoCheck()
钩子,无论变化发生在何处,每个变化检测周期都会以很大的频率调用这个钩子,比如只要把光标移动到另一个<input>
就会触发一次调用。如果使用这个钩子,那么你的实现必须非常轻量级,否则会损害用户体验。
8,组件之间交互:也就是让两个或多个组件之间共享信息的方法
- 父组件将值传给子组件:@Input() inputProp
- 子组件将值转给父组件(或者说父组件监听子组件的事件):@output() outPutEvent = new EventEmitter<string>();
- 父组件和子组件通过本地变量通信(父组件获得子组件中的数据,即方向同@output):<app-countdown-timer #timer></app-countdown-timer>
- 父子组件通过本地变量方法是个简单便利的方法。但是它也有局限性,因为父组件-子组件的连接必须全部在父组件的模板中进行。父组件本身的(类)代码对子组件没有访问权。
-
如果父组件的类需要读取子组件的属性值或调用子组件的方法,就不能使用本地变量方法。当父组件类需要这种访问时,可以把子组件作为 ViewChild,注入到父组件里面。
- 父组件调用 @ViewChild()
// 父组件(父类)中: @ViewChild(ChildComponent) private childComponent: ChildComponent; //将子组件注入变量childComponent中 或者这么用:在父模板中定义一个子组件的引用变量,然后传给父组件的@ViewChild()作为参数,如下: -- 父模板中: <child-component #child></child-component> // 父组件(父类)中: @ViewChild('child') private child:ChildComponent;
/*************说明****************/ 1, 被注入的子组件只有在 Angular 显示了父组件视图之后才能访问,即最早使用子组件的地方是生命周期钩子 ngAfterViewInit中。 -
父组件和子组件通过服务来通讯;在父组件的@Component元数据中定义 providers: [MissionService],则将此服务限定在父组件和子组件中,其他的组件无法使用此服务。
-
【扩展:viewChild的各种方式】:
1, 如上例,在父组件中使用viewChild,获取子组件,此时父模板中必须含有子组件的选择器。 2. 在ts文件中 使用viewChild,获取模板文件中元素或者<ng-template>元素,
例1,获取div元素: html模板文件:<div #myDiv></div> ts文件:@ViewChild("myDiv", {static: true}) private myDivElem: ElementRef<any> | null; //获取到此DOM元素后便可以对此DOM元素进行各种操作了。 console.log(myDivElem); myDivElem.nativeElement; myDivElem.nativeElement.value = null;
例2,获取ng-template模板 html模板文件:<ng-template #myTemplate></ng-template> ts文件:@ViewChild("myTemplate", {static: true}) private myTemplateRef: TemplateRef<any>|null;
9,组件样式:
10,动态组件
- Angular 自带的 API 就能支持动态加载组件。
- 参见文档例子。
11,angular元素
- Angular 元素就是打包成自定义元素的 Angular 组件。
- 参见文档
二,表单与用户输入
1, angular表单简介:Angular 提供了两种不同的方法来通过表单处理用户输入:响应式表单和模板驱动表单。
- 响应式表单: <input type="text" [formControl]="favoriteColorControl"> , favoriteColorControl = new FormControl('');
- 模板驱动表单: <input type="text" [(ngModel)]="favoriteColor"> , favoriteColor = '';
2,响应式表单
- 1
3, 验证表单输入
4, 构建动态表单
三,Observable 与 RxJS
四,
1
1
1
1
1
1
1
1
1
1
1
1
1