angular2实用技巧点滴

1. *ngFor

*ngFor指令定义了一些行属性:

export declare class NgForRow {
    $implicit: any;
    index: number;
    count: number;
    constructor($implicit: any, index: number, count: number);
    first: boolean;
    last: boolean;
    even: boolean;
    odd: boolean;
}

它们只能用在*ngFor语句中,如果在语句外部使用我们需要导出为局部变量。

<a *ngFor="let hero of heroes; let index = index">
    {{index + ". " + hero.name}}
</a>

$implicit为当前行本身,实际上就是我们这里的单个hero。其它几个属性都见名知意。

*ngFor的语句实际上属于Angular特有的微语法,它被Angular自身解析。

*ngFor正因为常常操作大量数据而应当在性能上被我们格外关注,首先*ngFor的改变规则

  1. 添加项目时,模板的新实例将添加到DOM。
  2. 当项目被删除时,其模板实例将从DOM中删除。
  3. 当项目重新排序时,它们各自的模板在DOM中重新排序。
  4. 否则,该项的DOM元素将保持不变。

以上的情况,*ngFor更新我们的视图都保持足够节源。

但也有些例外,比如当我们改变heroes的引用

heroes = heroes.concat(newHero);

*ngFor将重新渲染所有DOM,即便它只是增加了一个英雄。这种情况尤其发生在我们的列表数据从服务器更新下来时,它的每一次更新都差不多是一次引用的转变。

Angular为我们提供了NgForTrackBy指令,它被设置为组件内部类的一个函数,该函数要求返回资源被判断为没有变化的依据。

*ngFor = "let hero of heroes trackBy:trackByHeroes"

trackByHeroes(index : number, hero : Hero){
    return hero.id;
}

它可以接收两个参数,当前项索引和当前项原值,这里我们返回英雄的id值,表明两个id值如果一致,则他们是同一个英雄,此时不需要完全重新渲染该dom,而是复用它。

2. 指令加*的原因

语法糖,将总是展开为模板,例如

<span *ngIf="show" other="other">example</span>

*语法糖直接展开为

<template [ngIf]="show">
    <span other="other">example</span>
</template>

其中,ngIf使用方括号使得show作为变量解析,而不是通常html语义上的直接属性。

什么情况下使用*语法糖?

所有直接性控制元素渲染与否的指令需要使用*,例如*ngFor*ngIf*ngSwitchCase*ngPluralCase,它们都将被包裹在template内,根据表达式值判定是否被渲染。而ngSwitchngPlural总是显示,它们的下级指令才直接控制渲染,所以不使用*语法糖。

其它情况的指令,一般遵守一个规则:

  1. 需要从元素流入数据到内部类,使用()包裹指令,例如所有事件都是从元素触发从而流入内部类引发控制,所以事件指令都是用()
  2. 需要从内部类流出数据到元素,使用[]包括指令,例如ngIfngForngSwitch等,它们都需要以内部类的变量为判断依据,所以都需要使用[],只是ngIfngFor等由于涉及控制元素是否渲染,它们需要template参与,所以提供了*语法糖简化编写,内部依然是[]
  3. 需要双向流动数据的,使用[()],例如[(ngModel)]就是一个典例。

2. 模板输入变量和模板引用变量

在模板上定义,作用域只在模板内部的普通变量称为模板输入变量。例如

<li *ngFor="let hero of heroes"></li>

其中

let hero

定义了一个模板输入变量,它不能在模板外部使用。

模板引用变量是模板中对 DOM 元素或指令的引用,可在同一元素、兄弟元素或任何子元素中被使用。例如

//原生dom对象,使用#定义
<span #cur></span>

//原生dom对象,使用规范的ref-定义
<span ref-cur></span>

//被Angular封装的form对象
<form #curForm="ngForm">

    <input name="name" required [(ngModel)]="name">
    
    //提交按钮被Angular内置的表单验证控制
    <input type="submit" [disable]="!curForm.form.valid" value="提交">
</form>

3. 安全导航操作符?.和管道操作符|

this is my name {{my.name}}

类似上面的表达式,my对象如果为null将导致应用报错。我们可以手动判断,例如

this is my name {{my?my.name:''}}

this is my name {{my && my.name}}

应对这种情况,Angular提供了比较优雅的一个表达式操作符?.,当遇到空值时跳出,避免应用出错。更重要的是,它非常适合多重路径的处理。

this is my name {{my?.name}}
this is the test {{a?.b?.c?.d}}

至于管道操作符,它可以一级一级的流动,还可以使用:添加管道条件。

4. Angular的插值表达式什么不被支持?

  • 赋值 (=, +=, -=, ...)
  • new运算符
  • 使用;或,的链式表达式
  • 自增或自减操作符 (++和--)
  • 不支持位运算|和&
  • 具有新的模板表达式运算符,比如|和?.

除以上官方明确说明的不被支持,实际上也有更多是不支持的,例如console、typeof/instanceof操作符等。但我们能做到吗?当然可以,在内部类声明方法即可,模板可以调用内部类方法,所以也就解开了插值表达式的限制。例如我们需要判断是否数组:

//*.component.ts
isArray(arr){
  return Array.isArray(arr);
}
//*.component.html
*ngIf="isArray(arr)"

5. 分清property属性绑定和Attribute绑定

//完全等同的两种绑定
<img s rc="{{img_url}}" />
<img [src]="img_url" />

Angular只允许绑定元素已有的原生属性,例如img的src属性,不存在的会报错。

<img [myAttr]="img_attr" />

这时候我们只能使用Attribute绑定:

<img [attr.myAttr]="img_attr" />

像这种绑定方式还有下面的场景:

<img [class]="imgClass" />
<img [class.imgClass]="true" />

//当然,我们更倾向于使用ngClass来批量管理类名
<img [ngClass]="{imgClass : true}">

<span [style.color]="gray">cmx</span>
<span [style.background-color]="gray">cmx</span>

//跟单位
<span [style.font-size.em]="2">cmx</span>

//驼峰命名
<span [style.fontSize.em]="2">cmx</span>

//当然,我们还是有ngStyle作为批量管理的选择
<span [ngStyle]="{'font-size':'10px'}">cmx</span>

5. 路由返回两种方式

  1. 路由
constructor(
    private router : Router,
    private route : ActivatedRoute
){}
this.router.navigate(['../'],{relativeTo:this.route});
  1. location
constructor(
    private location : Location
){}
this.location.back();

6. 信任安全的值

angular2有自身的一套安全过滤系统,例如,动态绑定一个url,angular2会自动把它无害化,诸如使用:unsafe:xxx的手段。但有时候它会导致我们得不到预期的运行结果,例如当我们使用URL.createObjectUrl用于预览本地选择的图片时,直接将其对象赋值给img标签的src通常会由于该安全机制而失败。如果我们确信自己是对的,就有必要使用angular2提供的api信任它。

//注入DomSanitizer
constructor(
    private sanitizer : DomSanitizer
) { }

//根据需要调用下面的方法之一
sanitizer.bypassSecurityTrustHtml(html)
sanitizer.bypassSecurityTrustScript(script)
sanitizer.bypassSecurityTrustStyle(style)
sanitizer.bypassSecurityTrustUrl(url)
sanitizer.bypassSecurityTrustResourceUrl(rurl)

7. 编写一个图片加载完成的指令

目前的情况看来,angular2并没有提供图片load的事件绑定,有需要的话,自己编写也并不难

@Directive({
  selector: 'img[loaded]'
})
export class ImgLoadedDirective {

  @Input()
  loaded : any

  @Input()
  data : any

  constructor(renderer : Renderer, el : ElementRef) {
    renderer.listen(el.nativeElement, 'load', () => {
      this.loaded(this.data);
    });
  }

}

指令监听img标签的loaded属性,传入一个方法名,有必要的话还可以传入data,当img触发load事件时,会自动调用该方法并传入data。

//html
![](...)

//ts
load(data){
    dosomething;
}

8. ngFor中同时使用ngIf

在一个*ngFor中,如果同时使用了*ngIf将导致转化为template出错,那么*ngFor中我们如果也想条件性渲染部分跳过呢?放弃语法糖可以做到

<p *ngFor="let hero of heroes">{{hero.name}}<p>

/*====================*/

//只显示cmx除外的英雄
<template ngFor let-hero [ngForOf]="heroes">
    <p *ngIf="hero.name !== 'cmx'">{{hero.name}}</p>
</template>

9. 使用hash风格的路由

angular2默认采用HTML5的pushState来管理路由,它会导致前端路由与后端路由的冲突,例如当部署到nginx环境时,我们通过首页进入子路由一切正常,但是在子路由路径下,刷新就会报404了。默认情况下nginx会当成这个路径是实际web路径下的资源而去定位它,但可想而知实际是并不存在的。折中的方案可以改回hash风格:

RouterModule.forRoot(routes, {useHash: true})
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容