{{expression}}
[target]="expression"
bind-target="expression"
复制代码
单向从视图到数据源css
(target)="statement"
on-target="statement"
复制代码
双向html
[(target)]="expression"
bindon-target="expression"
复制代码
DOM property
的值能够改变;HTML attribute
的值不能改变。
在 Angular
的世界中,attribute
惟一的做用是用来初始化元素和指令的状态。
当进行数据绑定时,只是在与"元素和指令"的 "property
和事件"打交道,而 attribute
就彻底靠边站了。express
若是忘了加方括号,Angular
会把这个表达式当作字符串常量看待,并用该字符串来初始化目标属性。
下面这个例子把 HeroDetailComponent
的 prefix
属性初始化为固定的字符串"1+1",而不是模板表达式"2"。Angular
设置它,而后忘记它。json
<app-hero-detail prefix="1+1" [hero]="currentHero"></app-hero-detail>
复制代码
做为对比,[hero]
绑定是组件的 currentHero
属性的活绑定,它会一直随着更新。bootstrap
{{...}}
,先对双花括号中的表达式求值,再把求值的结果转换成字符串。 Angular
把这些插值表达式翻译成了相应的属性绑定。<p><img src="{{heroImageUrl}}"> is the <i>interpolated</i> image.</p>
<p><img [src]="heroImageUrl"> is the <i>property bound</i> image.</p>
复制代码
script
标签的 HTML
泄漏到浏览器中,两者都只渲染没有危害的内容。src/app/app.component.ts
evilTitle = 'Template <script>alert("evil never sleeps")</script>Syntax';
src/app/app.component.html
<p><span>"{{evilTitle}}" is the <i>interpolated</i> evil title.</span></p>
<p>"<span [innerHTML]="evilTitle"></span>" is the <i>property bound</i> evil title.</p>
复制代码
attribute
绑定 property
,而不用字符串设置元素的attribute
。 ARIA
, SVG
和 table
中的 colspan/rowspan
等 attribute
。 它们是纯粹的 attribute
,没有对应的属性可供绑定。 若是想写出相似下面这样的东西,就会暴露出痛点了:<tr><td colspan="{{1 + 1}}">Three-Four</td></tr>
复制代码
会获得这个错误:
Template parse errors: Can't bind to 'colspan' since it isn't a known native property
方括号中的部分不是元素的属性名,而是由attr
前缀,一个点 (.)
和 attribute
的名字组成segmentfault
<tr><td [attr.colspan]="1 + 1">One-Two</td></tr>
复制代码
( [(...)] )
双向绑定语法其实是属性绑定和事件绑定的语法糖。数组
NgClass
,能够同时添加或移除多个类。 把 ngClass
绑定到一个 key:value
形式的控制对象
(value
为boolean
值)src/app/app.component.html
浏览器
<div [ngClass]="currentClasses">This div is initially saveable, unchanged, and special</div>
复制代码
src/app/app.component.ts
安全
currentClasses: {};
setCurrentClasses() {
// CSS classes: added/removed per current state of component properties
this.currentClasses = {
'saveable': this.canSave,
'modified': !this.isUnchanged,
'special': this.isSpecial
};
}
复制代码
NgStyle
设置多个内联样式。NgStyle
须要绑定到一个 key:value
控制对象。 src/app/app.component.html
<div [ngStyle]="currentStyles">
This div is initially italic, normal weight, and extra large (24px).
</div>
复制代码
src/app/app.component.ts
bash
currentStyles: {};
setCurrentStyles() {
// CSS styles: set per current state of component properties
this.currentStyles = {
'font-weight': 'bold',
};
}
复制代码
hero
前的 let
关键字建立了一个名叫 hero
的模板输入变量。 这个变量的范围被限制在所重复模板的单一实例上。事实上,你能够在其它内置结构型指令中使用一样的变量名。#phone
的意思就是声明一个名叫 phone
的变量来引用 <input>
元素。 模板引用变量的做用范围是整个模板。不要在同一个模板中屡次定义同一个变量名,不然它在运行期间的值是没法肯定的。<input #phone placeholder="phone number">
复制代码
Input
)属性或输出(Output
)属性。 但Angular
须要@Input()
和@Output()
装饰器来标记出那些容许被外部组件绑定到的属性。 声明输入与输出属性:@Input() hero: Hero;
@Output() deleteRequest = new EventEmitter<Hero>();
复制代码
另外:@Input get/set
写法
_oprType: string ='VIEW';
@Input("oprType")
get oprType(){
retrun this._oprType;
}
set oprType(oprType){
this._oprType = oprType;
...//其余逻辑处理
}
复制代码
json
管道对调试绑定特别有用:src/app/app.component.html (pipes-json)
<div>{{currentHero | json}}</div>
复制代码
它生成的输出是这样的:
{ "id": 0, "name": "Hercules", "emotion": "happy",
"birthdate": "1970-02-25T08:00:00.000Z",
"url": "http://www.imdb.com/title/tt0065832/",
"rate": 325 }
复制代码
ngOnChanges()-》ngOnInit()-》ngDoCheck()-》ngAfterContentInit()-》ngAfterContentChecked()-》ngAfterViewInit()-》ngAfterViewChecked()-》ngOnDestroy()
ngOnInit
生命周期钩子会在 DOM
更新操做执行前触发
rxjs
知识var subject = new Subject<string>();
subject.next(1);
subject.subscribe({
next: (v) => console.log('observerA: ' + v)
});
//observerA: 1
复制代码
纯(pure
)管道与非纯(impure
)管道
默认状况下,管道都是纯的。 Angular
只有在它检测到输入值发生了纯变动时才会执行纯管道。
纯变动:是指对原始类型值(String、Number、Boolean、Symbol
)的更改,或者对对象引用(Date、Array、Function、Object
)的更改。 Angular
会忽略对象内部的更改。 若是你更改了输入日期(Date
)中的月份、往一个输入数组(Array
)中添加新值或者更新了一个输入对象(Object
)的属性,Angular
都不会调用纯管道。 Angular
会在每一个组件的变动检测周期中执行非纯管道。 非纯管道可能会被调用不少次,和每一个按键或每次鼠标移动同样频繁。
ElementRef
import { Directive, ElementRef } from '@angular/core';
@Directive({
selector: '[appHighlight]'
})
export class HighlightDirective {
constructor(el: ElementRef) {
el.nativeElement.style.backgroundColor = 'yellow';
}
}
复制代码
import
语句还从 Angular
的 core
库中导入了一个 ElementRef
符号。
你能够在指令的构造函数中注入 ElementRef
,来引用宿主 DOM
元素。 ElementRef
(对视图中某个宿主元素的引用)经过其 nativeElement
属性给了你直接访问宿主 DOM
元素的能力。
DOM
会致使你的应用在 XSS
攻击前面更加脆弱。当须要直接访问 当须要直接访问 DOM
时,请把本 API
做为最后选择。
优先使用 Angular
提供的模板和数据绑定机制。 或者你还能够看看 Renderer2
(实现自定义渲染器),它提供了可安全使用的 API
—— 即便环境没有提供直接访问原生元素的功能。
import { Directive, ElementRef, Renderer2 } from '@angular/core';
@Directive({
selector: '[appHighlight]'
})
export class HighlightDirective {
constructor(el: ElementRef, private renderer: Renderer2) {
//el.nativeElement.style.backgroundColor = 'yellow';
this.renderer.setStyle(this.el.nativeElement, "backgroundColor", 'yellow');
}
}
复制代码
HostListener
把一个事件绑定到一个宿主监听器,并提供配置元数据。@HostListener('mousedown') onMouseEnter() {
this.highlight(this.highlightColor || this.defaultColor || 'red');
}
复制代码
mousedown
要监听的事件。 当mousedown
事件发生时,Angular
就会执行所提供的处理器方法onMouseEnter
。
@Input
。 @Input
装饰器。 ([ ])
中时,该属性属于其它组件或指令,它必须带有 @Input
装饰器。<p [appHighlight]="color">Highlight me!</p>
复制代码
color
属性位于右侧的绑定表达式中,它属于模板所在的组件。 该模板和组件相互信任。所以 color
不须要 @Input
装饰器。 appHighlight
属性位于左侧,它引用了 HighlightDirective
中一个带别名的属性,它不是模板所属组件的一部分,所以存在信任问题。 因此,该属性必须带 @Input
装饰器。
bootstrap
—— 根组件,Angular
建立它并插入 index.html
宿主页面。(*)
写法是个语法糖,Angular
会把它解开成一个 <ng-template>
标记,包裹着宿主元素及其子元素。 Angular
会在真正渲染的时候填充 <ng-template>
的内容,而且把 <ng-template>
替换为一个供诊断用的注释。<ng-template let-hero="hero">
<div *ngIf="hero" [class.odd]="odd">({{i}}) {{hero.name}}</div>
</ng-template>
复制代码
<ng-template>
中,那些元素就是不可见的(被注释掉了)。*ngFor
和 *ngIf
不能放在同一个宿主元素上。 *ngFor
放在一个"容器"元素上,再包装进 *ngIf
元素。 这个元素可使用ng-container
,以避免引入一个新的 HTML
层级。<ul>
<ng-container *ngFor="let menu of menus">
<li *ngIf="!menu.children?.length">
</li>
</ng-container>
</ul>
复制代码
Angular
的 <ng-container>
是一个分组元素,但它不会污染样式或元素布局,由于 Angular
压根不会把它放进 DOM
中。
template: <ng-template #toolbarTemplate [ngTemplateOutletContext]="{ $implicit: this}"></ng-template>
class: @ViewChild("toolbarTemplate") toolbarTemplate: TemplateRef<any>
简化写法:
<ng-template [ngTemplateOutlet]="toolbarTemplate || defaultToolbarTemplate"
[ngTemplateOutletContext]="{ $implicit: this}"></ng-template>
复制代码
该指令用于基于已有的 TemplateRef 对象,插入对应的内嵌视图。在应用 NgTemplateOutlet 指令时,咱们能够经过 [ngTemplateOutletContext] 属性来设置 EmbeddedViewRef 的上下文对象。绑定的上下文应该是一个对象,此外可经过 let语法来声明绑定上下文对象属性名。
angular6.x中ngTemplateOutlet指令的使用示例
表达式中的上下文变量是由"模板引用变量#aa
"、"模板输入变量let bb
"和"组件的成员cc
"叠加而成的。
优先级:模板输入变量>模板引用变量>指令的上下文变量>组件类的实例
模板表达式不能引用全局命名空间中的任何东西,好比window
和document
。它们也不能调用console.log
或Math.max
。它们只能引用表达式上下文中的内容。
声明式组件和入口组件:
声明式组件会在模板中经过组件声明的selector
(好比<cmb></cmb>
)加载组件。
入口组件entryComponents
主要有3类:
@NgModule
中的bootstrap
声明的根组件exports
a
的ngModule
中exports
出一组组件、指令和管道 b
导入了模块a
b
下的全部组件的模板,均可以使用模块a
的ngModule
中exports
出的组件、指令和管道<div class="seconds">{{timer.seconds}}</div>
<app-countdown-timer #timer></app-countdown-timer>
复制代码
这个本地变量方法#timer
是个简单便利的方法。可是它也有局限性,由于父组件-子组件的链接必须所有在父组件的html
模板中进行。父组件自己的ts
代码对子组件没有访问权。
当父组件类ts
须要这种访问时,能够把子组件做为 ViewChild
,注入到父组件里面。@ViewChild('timer') timer;
ng-content
父组件页面parent.html
<attchment-upload>abcde</attchment-upload>
复制代码
被父组件包含的子组件标签页面attchment-upload.html
<div>-- begins --</div>
<ng-content></ng-content>
<div>-- ends --</div>`
复制代码
输出:
-- begins --
abcde
-- ends --
复制代码
以上<ng-content>
标签是父组件页面中外来内容的占位符。 它指明在子组件标签页面的哪里插入这些父组件的外来内容abcde
。
注意:不要在组件标签的内部听任何内容 —— 除非你想把这些内容投影进这个组件中。
<ng-container *ngTemplateOutlet="greet"></ng-container>
<ng-template #greet><span>Hello</span></ng-template>
复制代码
或者
<ng-container *ngTemplateOutlet="contentTemplate"></ng-container>
contentTemplate:TemplateRef<any>
this.contentTemplate=...
//TemplateRef就是对应html中的ng-template标签
复制代码
ngIf
写法<ng-container *ngIf="a.length==0; else elseTemplate">
...
</ng=container>
<ng-template #elseTemplate>
...
</ng-template>
复制代码
30.ngTemplateOutletContext
<ng-template let-rowData let-rowIndex="rowIndex" let-columns="columns">
<tr>
<td *ngFor="let col of columns;">
// 经过 [ngTemplateOutletContext] 属性来设置 EmbeddedViewRef:commonBodyTemplate的上下文对象
<ng-container *ngTemplateOutlet="commonBodyTemplate;context:{$implicit:col,rowIndex:rowIndex,rowData:rowData,columns:columns}"></ng-container>
</td>
</tr>
</ng-template>
//若 let 语法未绑定任何属性名(let-col),则上下文对象中 $implicit 属性,对应的值col将做为默认值。
<ng-template #commonBodyTemplate let-col let-rowIndex="rowIndex" let-rowData="rowData">
<ng-container *ngIf="col.field=='idx'">
{{rowIndex+1}}
</ng-container>
<ng-container *ngIf="col.field=='attachSize'">
{{(rowData[col.field]||"--")+(rowData["attachSizeUnit"]||"")}}
</ng-container>
<ng-container *ngIf="editable;else elseTemplate">
<ng-container *ngIf="col.field=='fileName'">
<ng-container *ngIf="rowData['attachmentId']">
<a [href]="attachUrls[rowData['attachmentId']]" [download]="rowData[col.field]">{{rowData[col.field]||""}}</a>
</ng-container>
</ng-container>
<ng-container *ngIf="['idx','attachSize','fileName'].indexOf(col.field)==-1">
{{rowData[col.field]||"--"}}
</ng-container>
</ng-container>
<ng-template #elseTemplate>
<ng-container *ngIf="['idx','attachSize'].indexOf(col.field)==-1">
{{rowData[col.field]||"--"}}
</ng-container>
</ng-template>
</ng-template>
复制代码
在父页面中嵌入<app-attachment></app-attachment>
报错:"app-attachment" is not a unknown element.
缘由:app-attachment
子页面模板对应的ts
组件没有包括在父页面所在的module
中。
32.@Input('companyId') companyId: string;
子组件的初始化constructor
取不到companyId
值,ngOnInit()
能够 因此初始化放在ngOnInit
中。
33.响应式表单
this.formGroup=fb.group({
contractid:["123",[Validators.required]],
});
this.theDetailGroup.get("finProductName").setValue(this.finProductName);
this.formGroup.get("docmentId").valueChanges.subscribe(value=>{
if(this.existList.findIndex(item=>item.docmentId==value)>-1){
this.formGroup.get("docmentId").setErrors({duplicate:true});
}
});
this.formGroup.get("docmentId").value;
复制代码
34.this.fb.group({})
响应式表单控件绑定,应该在生命周期以前,即constructor
构造函数中初始化。由于若是放在ngOnInit
中绑定,在表单初始化前对表单进行赋值操做,会报错。
35.自定义模块中exports
使用
将附件声明到公用模块
import { NgModule } from '@angular/core';
import { CommonModule} from '@angular/common';
import { AttachmentComponent } from './attachment.component';
@NgModule({
imports: [
CommonModule,
],
exports:[
CommonModule,
AttachmentComponent
],
providers:[],
declarations: [
AttachmentComponent
],
entryComponents:[
AttachmentComponent
]
})
export class SharedModule { }
复制代码
宿主组件所在的module
中引入公共模块
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SharedModule } from 'src/app/shared';
@NgModule({
declarations: [
],
imports: [
CommonModule,
SharedModule
],
entryComponents:[]
})
export class MineModule { }
复制代码
36.自定义双向数据绑定
<app-base [(companyId)]="companyId"></app-base>
复制代码
app-base.ts
_companyId = '';
@Output() companyIdChange = new EventEmitter();
@Input('companyId')
get companyId() {
return this._companyId;
}
set companyId(companyId) {
this._companyId = companyId;
this.companyIdChange.emit(companyId);
}
复制代码
注意:属性名 + Change
是双向绑定中Output
的固定写法
37.在使用一些第三方的组件的时候,要修改组件的样式。 这种状况下使用:
:host ::ng-deep .className{
新的样式......
}
复制代码
38.要在html
直接使用某个变量。ts
中能够不要定义这个变量,直接get
。
html:
<div *ngIf="isStatusOkey"></div>
ts:
get isStatusOkey() {
return this.baseInfoConfig.baseInfoData['lpIndentifyStatus'] !== 'OKAY';
}
html:
<mat-grid-tile *ngFor="let item of attachmentTypeList"></mat-grid-tile> ts: get attachmentTypeList() { return this.attachService.getAttachmentTypeList(); } 复制代码