Angular-难点

栏目: 编程语言 · AngularJS · 发布时间: 5年前

内容简介:从视图到数据源的单向绑定双向作为对比,
  1. 单向从数据源到视图
{{expression}}
[target]="expression"
bind-target="expression"
复制代码

从视图到数据源的单向绑定

(target)="statement"
on-target="statement"
复制代码

双向

[(target)]="expression"
bindon-target="expression"
复制代码
  1. DOM property 的值可以改变; HTML attribute 的值不能改变。 在 Angular 的世界中, attribute 唯一的作用是用来初始化元素和指令的状态。 当进行数据绑定时,只是在与元素和指令的 property 和事件打交道,而 attribute 就完全靠边站了。

  2. 如果忘了加方括号, Angular 会把这个表达式当做字符串常量看待,并用该字符串来初始化目标属性。 下面这个例子把 HeroDetailComponentprefix 属性初始化为固定的字符串"1+1",而不是模板表达式"2"。 Angular 设置它,然后忘记它。

<app-hero-detail prefix="1+1" [hero]="currentHero"></app-hero-detail>
复制代码

作为对比, [hero] 绑定是组件的 currentHero 属性的活绑定,它会一直随着更新。

  1. 插值表达式 {{...}} ,先对双花括号中的表达式求值,再把求值的结果转换成字符串。 实际上,在渲染视图之前, Angular 把这些插值表达式翻译成了相应的属性绑定。 但数据类型不是字符串时,就必须使用属性绑定了。
<p><img src="{{heroImageUrl}}"> is the <i>interpolated</i> image.</p>
<p><img [src]="heroImageUrl"> is the <i>property bound</i> image.</p>
复制代码
  1. 不管是插值表达式还是属性绑定,都不会允许带有 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>

复制代码
  1. attribute 绑定 一般情况下,我们通过属性绑定来设置元素的属性 property ,而不用字符串设置元素的 attribute 。 考虑 ARIASVGtable 中的 colspan/rowspanattribute 。 它们是纯粹的 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>
复制代码
  1. 双向数据绑定 ( [(...)] ) 想象盒子里的香蕉来记住方括号套圆括号 [()] 。 双向绑定语法实际上是属性绑定和事件绑定的语法糖。

  2. 内置属性型指令

  • a.通过绑定到 NgClass ,可以同时添加或移除多个类。 把 ngClass 绑定到一个 key:value 形式的控制对象( valueboolean 值)
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>
复制代码
  1. 模板输入变量: hero 前的 let 关键字创建了一个名叫 hero 的模板输入变量。 这个变量的范围被限制在所重复模板的单一实例上。事实上,你可以在其它内置结构型指令中使用同样的变量名。 模板引用变量: #phone 的意思就是声明一个名叫 phone 的变量来引用 <input> 元素。
<input #phone placeholder="phone number">
复制代码

模板引用变量的作用范围是整个模板。不要在同一个模板中多次定义同一个变量名,否则它在运行期间的值是无法确定的。

  1. 你总是可以在组件自己的模板中绑定到组件的公共属性,而不用管它们是否输入( Input )属性或输出( Output )属性。 但 Angular 需要 @Input()@Output() 装饰器来标记出那些允许被外部组件绑定到的属性。 声明输入与输出属性:
@Input()  hero: Hero;
    @Output() deleteRequest = new EventEmitter<Hero>();
复制代码

另外,还可以在指令元数据的 inputsoutputs 数组中标记出这些成员。比如这个例子:

@Component({
    inputs: ['hero'],
    outputs: ['deleteRequest'],
    })
复制代码
  1. 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 }
复制代码
  1. 构造函数在所有的生命周期钩子之前执行。

ngOnChanges()-》ngOnInit()-》ngDoCheck()-》ngAfterContentInit()-》ngAfterContentChecked()-》ngAfterViewInit()-》ngAfterViewChecked()-》ngOnDestroy()

  1. rxjs 知识
var subject = new Subject<string>();
subject.next(1);
subject.subscribe({
  next: (v) => console.log('observerA: ' + v)
});
//observerA: 1
复制代码
  1. 纯( pure )管道与非纯( impure )管道: 默认情况下,管道都是纯的。 Angular 只有在它检测到输入值发生了纯变更时才会执行纯管道。 纯变更是指对原始类型值( String、Number、Boolean、Symbol )的更改,或者对对象引用( Date、Array、Function、Object )的更改。 Angular 会忽略对象内部的更改。 如果你更改了输入日期( Date )中的月份、往一个输入数组( Array )中添加新值或者更新了一个输入对象( Object )的属性, Angular 都不会调用纯管道。 Angular 会在每个组件的变更检测周期中执行非纯管道。 非纯管道可能会被调用很多次,和每个按键或每次鼠标移动一样频繁。

  2. ElementRef

import { Directive, ElementRef } from '@angular/core';
@Directive({
  selector: '[appHighlight]'
})
export class HighlightDirective {
    constructor(el: ElementRef) {
       el.nativeElement.style.backgroundColor = 'yellow';
    }
}
复制代码

import 语句还从 Angularcore 库中导入了一个 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');
    }
}
复制代码
  1. HostListener 把一个事件绑定到一个宿主监听器,并提供配置元数据。
@HostListener('mousedown') onMouseEnter() {
  this.highlight(this.highlightColor || this.defaultColor || 'red');
}
复制代码

mousedown 要监听的事件。 当 mousedown 事件发生时, Angular 就会执行所提供的处理器方法 onMouseEnter

  1. 你可以根据属性名在绑定中出现的位置来判定是否要加 @Input 。 当它出现在等号右侧的模板表达式中时,它属于模板所在的组件,不需要 @Input 装饰器。 当它出现在等号左边的方括号([ ])中时,该属性属于其它组件或指令,它必须带有 @Input 装饰器。
<p [appHighlight]="color">Highlight me!</p>  
复制代码

color 属性位于右侧的绑定表达式中,它属于模板所在的组件。 该模板和组件相互信任。因此 color 不需要 @Input 装饰器。 appHighlight 属性位于左侧,它引用了 HighlightDirective 中一个带别名的属性,它不是模板所属组件的一部分,因此存在信任问题。 所以,该属性必须带 @Input 装饰器。

  1. bootstrap —— 根组件, Angular 创建它并插入 index.html 宿主页面。
  2. 结构型指令中,星号(*)写法是个语法糖, 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> 中,那些元素就是不可见的(被注释掉了)。

  1. 每个宿主元素上只能有一个结构型指令=》 *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>
复制代码
  1. 表达式中的上下文变量是由模板引用变量 #aa 、模板输入变量 let bb 和组件的成员 cc 叠加而成的。 那么优先级,模板输入变量>模板引用变量>指令的上下文变量>组件类的实例

  2. 模板表达式不能引用全局命名空间中的任何东西,比如 windowdocument 。 它们也不能调用 console.logMath.max 。它们只能引用表达式上下文中的内容。

  3. 声明式组件和入口组件: 声明式组件会在模板中通过组件声明的 selector (比如 <cmb></cmb> )加载组件 入口组件 entryComponents 主要有3类: (1)在 @NgModule 中的 bootstrap 声明的根组件 (2)路由配置的组件 (3)动态组件

  4. ngModule 中的 exports 在模块a的 ngModuleexports 出一组组件、指令和管道-》模板b导入了模块a-》模块b下的所有组件的模板,都可以使用模块a的 ngModuleexports 出的组件、指令和管道

  5. 父子组件交互

<div class="seconds">{{timer.seconds}}</div>
<app-countdown-timer #timer></app-countdown-timer>
复制代码

这个本地变量方法是个简单便利的方法。但是它也有局限性,因为父组件-子组件的连接必须全部在父组件的 html 模板中进行。父组件本身的 ts 代码对子组件没有访问权。

当父组件类需要这种访问时,可以把子组件作为 ViewChild ,注入到父组件里面。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

计算机程序设计艺术・卷3

计算机程序设计艺术・卷3

[美] 高德纳(Donald E. Knuth) / 贾洪峰 / 人民邮电出版社 / 2017-2 / 198.00元

《计算机程序设计艺术》系列被公认为计算机科学领域的权威之作,深入阐述了程序设计理论,对计算机领域的发展有着极为深远的影响。本书为该系列的第3卷,全面讲述了排序和查找算法。书中扩展了卷1中数据结构的处理方法,并对各种算法的效率进行了大量的分析。一起来看看 《计算机程序设计艺术・卷3》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

URL 编码/解码
URL 编码/解码

URL 编码/解码

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换