Angular-难点

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

内容简介:从视图到数据源的单向绑定双向作为对比,
  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 ,注入到父组件里面。


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

查看所有标签

猜你喜欢:

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

Practical Vim, Second Edition

Practical Vim, Second Edition

Drew Neil / The Pragmatic Bookshelf / 2015-10-31 / USD 29.00

Vim is a fast and efficient text editor that will make you a faster and more efficient developer. It’s available on almost every OS, and if you master the techniques in this book, you’ll never need an......一起来看看 《Practical Vim, Second Edition》 这本书的介绍吧!

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

多种字符组合密码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

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

UNIX 时间戳转换