装饰器

  1. @Component({
  2. selector: 'app-heroes',
  3. templateUrl: './heroes.component.html',
  4. styleUrls: ['./heroes.component.less'],
  5. // 当前组件所需的服务提供商的一个数组。
  6. // 在这个例子中,它告诉 Angular 该如何提供一个 HeroService 实例,以获取要显示的英雄列表。
  7. providers: [HeroService],
  8. // template: '<div class="container">这是一个内联模板</div>'
  9. });

模板

HTML

、 和 元素这个舞台上中并没有扮演有用的角色。

插值与模板表达式

  • {{ 1+1 }}是插值表达式
  • 1+1是模板表达式
  • 表达式可以调用宿主组件的方法:{{1 + 1 + getVal()}}

    表达式上下文

  • 典型的表达式上下文就是这个组件实例

  • 表达式的上下文可以包括组件之外的对象。 比如 模板输入变量 (let customer) 和模板引用变量 (#customerInput)
  • 表达式中的上下文变量是由 模板变量指令的上下文变量 (如果有)和 组件的成员 叠加而成的

    模板语句

绑定

模板绑定是通过 property 和事件来工作的,而不是 attribute。

属性绑定

也不能使用属性 绑定 来调用目标元素上的方法。 如果这个元素触发了事件,可以通过事件绑定来监听它们。 如果必须读取目标元素上的属性或调用它的某个方法,得用另一种技术。 参见 API 参考手册中的 ViewChildContentChild

绑定目标

  • 元素指令,如[src]
  • 属性型指令的属性名,如[ngClass]
  • 输入属性,即父子通信的属性,如[hero]

    消除副作用

    一般建议是,只绑定数据属性和那些只返回值而不做其它事情的方法。

    属性绑定还是插值

  • 建议建立代码风格规则,选择一种形式

  • 但数据类型不是字符串时,就必须使用属性绑定了。
    1. <p><img src="{{heroImageUrl}}"> is the <i>interpolated</i> image.</p>
    2. <p><img [src]="heroImageUrl"> is the <i>property bound</i> image.</p>

    attribute, class, style绑定

    attribute,对于无法绑定property的例外情况

    angular6 中的 property-binding 和 attribute-binding
    1. <tr><td [attr.colspan]="1 + 1">One-Two</td></tr>
    2. <button [attr.aria-label]="actionName">{{actionName}} with Aria</button>

    class绑定

    1. // CSS 类绑定 是添加或删除单个类的最佳途径。
    2. <li [class.selected]="hero === selectedHero"></li>
    3. <div class="special" [class.special]="!isSpecial">This one is not so special</div>
    4. // 如果badCurly有值会全部覆盖
    5. <div class="bad curly special" [class]="badCurly">Bad curly</div>
    1. // 同时添加或移除多个 CSS 类时,NgClass 指令可能是更好的选择
    2. <div [ngClass]="currentClasses">[ngClass] binding to the classes property</div>
    1. this.currentClasses = {
    2. 'saveable': this.canSave,
    3. 'modified': !this.isUnchanged
    4. };

    style绑定

    1. // 样式绑定是设置单一样式值的简单方式。
    2. <button [style.font-size.%]="!isSpecial ? 150 : 50" >Small</button>
  1. // 如果要同时设置多个内联样式,NgStyle 指令可能是更好的选择。
  2. <div [ngStyle]="currentStyles">lyy</div>
  1. this.currentStyles = {
  2. 'font-style': this.canSave ? 'italic' : 'normal',
  3. 'font-size': this.isSpecial ? '24px' : '12px'
  4. };

注意,样式属性命名方法可以用中线命名法,像上面的一样 也可以用驼峰式命名法,如 fontSize。

事件绑定

  • 匹配到元素事件或已知指令的输出属性(自定义事件)
  • 绑定会通过名叫 $event 的事件对象传递关于此事件的信息

    使用 EventEmitter 实现自定义事件

    ```typescript @Output() deleteRequest = new EventEmitter();

delete() { this.deleteRequest.emit(this.item); }

  1. <a name="wEf5C"></a>
  2. ### 双向绑定
  3. 虽然 ngModel 是一个有效的 Angular 指令,不过它在默认情况下是不可用的。它属于一个可选模块 FormsModule,你必须自行添加此模块才能使用该指令。
  4. <a name="d0ZH2"></a>
  5. #### input 非双向绑定
  6. ```html
  7. <input #heroName />
  8. <button (click)="add(heroName.value); heroName.value=''">

父子组件双向绑定

  1. <app-sizer [(size)]="fontSizePx"></app-sizer>

表单双向绑定

需模块 FormsModule
你不能把ngModel用到非表单类的原生元素或第三方自定义组件上,除非写一个合适的值访问器,这种技巧超出了本章的范围。

  1. <input [(ngModel)]="selectedHero.name" placeholder="name"/>

展开形式

[(ngModel)] 语法只能设置数据绑定属性。 如果要做更多或者做点不一样的事,也可以写它的展开形式。

  1. <input
  2. [ngModel]="currentHero.name"
  3. (ngModelChange)="setUppercaseName($event)">

指令(结构型和属性型)

*ngFor

[ngFor](https://angular.cn/api/common/NgForOf) 可以为任何可迭代的 (iterable) 对象重复渲染条目。

  1. <li *ngFor="let hero of heroes; let i=index; trackBy: trackByHeroes">
  2. <li *ngFor="let hero of heroes; index as i; trackBy: trackByHeroes">

带 trackBy 的 *ngFor

往组件中添加一个方法,它会返回 NgFor应该追踪的值。 在这里,这个值就是英雄的 id。
即重新请求的数据,只有id变化了的才重新渲染。(注意这只是简单的情况,仅关注id)

  1. <div *ngFor="let item of items; trackBy: trackByItems">
  2. ({{item.id}}) {{item.name}}
  3. </div>
  1. class H {
  2. trackByHeroes(index: number, hero: Hero): number { return hero.id; }
  3. }

*ngIf

  1. <div *ngIf="selectedHero">
  2. </div>

当 selectedHero 为 undefined 时,ngIf 从 DOM 中移除了英雄详情。因此也就不用担心 selectedHero 的绑定了。 当用户选择一个英雄时,selectedHero 也就有了值,并且 ngIf 把英雄的详情放回到 DOM 中。

显示/隐藏的技术对于只有少量子元素的元素是很好用的,但要当心别试图隐藏大型组件树。相比之下,NgIf 则是个更安全的选择。

How to use *ngIf else?

NgSwitch

  1. <div [ngSwitch]="currentHero.emotion">
  2. <app-happy-hero *ngSwitchCase="'happy'" [hero]="currentHero"></app-happy-hero>
  3. <app-sad-hero *ngSwitchCase="'sad'" [hero]="currentHero"></app-sad-hero>
  4. <app-confused-hero *ngSwitchCase="'confused'" [hero]="currentHero"></app-confused-hero>
  5. <app-unknown-hero *ngSwitchDefault [hero]="currentHero"></app-unknown-hero>
  6. </div>

模板引用变量

模板引用变量的作用范围是整个模板。

  1. <input #phone placeholder="phone number"> // #
  2. <input ref-address placeholder="home address"> // ref
  3. <button (click)="callPhone(phone.value)">Call</button>

不过,指令也可以修改这种行为,让这个值引用到别处,比如它自身。 NgForm 指令就是这么做的。

  1. <form (ngSubmit)="onSubmit(heroForm)" #heroForm="ngForm">
  2. <!-- ... -->
  3. <!-- 这里的 heroForm 实际上是一个 Angular NgForm 指令的引用 -->
  4. <button type="submit" [disabled]="!heroForm.form.valid">Submit</button>
  5. </form>

输入输出属性

  1. // 方式2
  2. @Component({
  3. inputs: ['hero'],
  4. outputs: ['deleteRequest']
  5. });
  6. // 方式1
  7. export class HeroDetailComponent {
  8. @Input() hero: Hero;
  9. @Output() deleteRequest = new EventEmitter<Hero>();
  10. }