内容简介:从视图到数据源的单向绑定双向作为对比,
- 单向从数据源到视图
{{expression}} [target]="expression" bind-target="expression" 复制代码
从视图到数据源的单向绑定
(target)="statement" on-target="statement" 复制代码
双向
[(target)]="expression" bindon-target="expression" 复制代码
-
DOM property
的值可以改变;HTML attribute
的值不能改变。 在Angular
的世界中,attribute
唯一的作用是用来初始化元素和指令的状态。 当进行数据绑定时,只是在与元素和指令的property
和事件打交道,而attribute
就完全靠边站了。 -
如果忘了加方括号,
Angular
会把这个表达式当做字符串常量看待,并用该字符串来初始化目标属性。 下面这个例子把HeroDetailComponent
的prefix
属性初始化为固定的字符串"1+1",而不是模板表达式"2"。Angular
设置它,然后忘记它。
<app-hero-detail prefix="1+1" [hero]="currentHero"></app-hero-detail> 复制代码
作为对比, [hero]
绑定是组件的 currentHero
属性的活绑定,它会一直随着更新。
-
插值表达式 {{...}} ,先对双花括号中的表达式求值,再把求值的结果转换成字符串。
实际上,在渲染视图之前,
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
的名字组成
<tr><td [attr.colspan]="1 + 1">One-Two</td></tr> 复制代码
-
双向数据绑定
( [(...)] )
想象盒子里的香蕉来记住方括号套圆括号[()]
。 双向绑定语法实际上是属性绑定和事件绑定的语法糖。 -
内置属性型指令
-
a.通过绑定到
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 }; } 复制代码
-
b.通过绑定
NgStyle
设置多个内联样式。NgStyle
需要绑定到一个key:value
控制对象。
src/app/app.component.ts currentStyles: {}; setCurrentStyles() { // CSS styles: set per current state of component properties this.currentStyles = { 'font-style': this.canSave ? 'italic' : 'normal', 'font-weight': !this.isUnchanged ? 'bold' : 'normal', 'font-size': this.isSpecial ? '24px' : '12px' }; } src/app/app.component.html <div [ngStyle]="currentStyles"> This div is initially italic, normal weight, and extra large (24px). </div> 复制代码
-
模板输入变量:
hero
前的let
关键字创建了一个名叫hero
的模板输入变量。 这个变量的范围被限制在所重复模板的单一实例上。事实上,你可以在其它内置结构型指令中使用同样的变量名。 模板引用变量:#phone
的意思就是声明一个名叫phone
的变量来引用<input>
元素。
<input #phone placeholder="phone number"> 复制代码
模板引用变量的作用范围是整个模板。不要在同一个模板中多次定义同一个变量名,否则它在运行期间的值是无法确定的。
-
你总是可以在组件自己的模板中绑定到组件的公共属性,而不用管它们是否输入(
Input
)属性或输出(Output
)属性。 但Angular
需要@Input()
和@Output()
装饰器来标记出那些允许被外部组件绑定到的属性。 声明输入与输出属性:
@Input() hero: Hero; @Output() deleteRequest = new EventEmitter<Hero>(); 复制代码
另外,还可以在指令元数据的 inputs
或 outputs
数组中标记出这些成员。比如这个例子:
@Component({ inputs: ['hero'], outputs: ['deleteRequest'], }) 复制代码
-
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()
-
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
的 是一个分组元素,但它不会污染样式或元素布局,因为 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> 复制代码
-
表达式中的上下文变量是由模板引用变量
#aa
、模板输入变量let bb
和组件的成员cc
叠加而成的。 那么优先级,模板输入变量>模板引用变量>指令的上下文变量>组件类的实例 -
模板表达式不能引用全局命名空间中的任何东西,比如
window
和document
。 它们也不能调用console.log
或Math.max
。它们只能引用表达式上下文中的内容。 -
声明式组件和入口组件: 声明式组件会在模板中通过组件声明的
selector
(比如<cmb></cmb>
)加载组件 入口组件entryComponents
主要有3类: (1)在@NgModule
中的bootstrap
声明的根组件 (2)路由配置的组件 (3)动态组件 -
ngModule
中的exports
在模块a的ngModule
中exports
出一组组件、指令和管道-》模板b导入了模块a-》模块b下的所有组件的模板,都可以使用模块a的ngModule
中exports
出的组件、指令和管道 -
父子组件交互
<div class="seconds">{{timer.seconds}}</div> <app-countdown-timer #timer></app-countdown-timer> 复制代码
这个本地变量方法是个简单便利的方法。但是它也有局限性,因为父组件-子组件的连接必须全部在父组件的 html
模板中进行。父组件本身的 ts
代码对子组件没有访问权。
当父组件类需要这种访问时,可以把子组件作为 ViewChild
,注入到父组件里面。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 工业大数据可视化面临的难点
- 结合实例浅析壳编写的流程与难点
- 微服务架构谈(八):拆分单体应用的难点
- OpenStack 学习有哪些难点?需要哪些知识储备?
- 知识图谱发展的难点&构建行业知识图谱的重要性
- 中间件(WAS、WMQ)运维 9个常见难点解析
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Web 2.0 Heroes
Bradley L. Jones / Wiley / 2008-04-14 / USD 24.99
Web 2.0 may be an elusive concept, but one thing is certain: using the Web as merely a means of retrieving and displaying information is history. Today?s Web is immediate, interactive, innovative. It ......一起来看看 《Web 2.0 Heroes》 这本书的介绍吧!