今天,我们要讲的是structural directives和组件生命周期这两个知识点。structural directives顾名思义就是改变dom结构的指令。著名的内建结构指令有 ngIfngSwitch and ngFor

例子

例子是我自己改写的,编写一个structural directives,然后通过这个指令实例化和注销组件,在此同时监视组件生命周期。

源代码

UnlessDirective

这个指令是官网示例中的指令。

app/unless.directive.ts

import {Directive, Input} from 'angular2/core';
import {TemplateRef, ViewContainerRef} from 'angular2/core';
@Directive({ selector: '[myUnless]' })
export class UnlessDirective {
  constructor(
    private _templateRef: TemplateRef,
    private _viewContainer: ViewContainerRef
    ) { }
  @Input() set myUnless(condition: boolean) {
    if (!condition) {
      this._viewContainer.createEmbeddedView(this._templateRef);
    } else {
      this._viewContainer.clear();
    }
  }
}

通过注入TemplateRef, ViewContainerRef这两个服务,来控制template的实例化和注销。TemplateRef可以让我们获取指令所在的元素的template,ViewContainerRef提供了多种视图容器的方法。

更详细的介绍:

用于测试的组件

接下来我们编写一个用于测试的组件。

app/lifecycle.ts

import {Component,Input} from 'angular2/core';
import {bootstrap} from 'angular2/platform/browser';
import {OnChanges, SimpleChange,OnInit,AfterContentInit,AfterContentChecked,AfterViewInit,AfterViewChecked,OnDestroy} from 'angular2/core';

@Component({
    selector: "lifecycle",
    template: `
    <div>
    <span>{{name}}</span>
     <button (click)="doSomething()">click and watch the lifecycle</button>
     </div>
    `
})
export class Lifecycle
implements OnChanges, OnInit,AfterContentInit,AfterContentChecked,AfterViewInit, AfterViewChecked, OnDestroy{
    @Input()
    name:string
    doSomething(){
        console.log('***********doSomething**********');
        setTimeout(()=>{
             console.log('***********setTimeout**********');
            this.name='susan'
        },1000)
    }
    ngOnInit(){console.log('onInit');}
    ngOnDestroy(){console.log('OnDestroy')}
    ngOnChanges(changes: {[propertyName: string]: SimpleChange}){console.log('ngOnChanges',changes)}
    ngAfterContentInit(){console.log('AfterContentInit')}
    ngAfterContentChecked(){console.log('AfterContentChecked')}
    ngAfterViewInit(){console.log('AfterViewInit')}
    ngAfterViewChecked(){console.log('AfterViewChecked')}
}

这段代码我们做了这些事:

  1. 渲染一个span一个button
  2. 设置成员变量name,@input代表从parent输入
  3. 设置成员函数doSomething,打印一个信息,执行一个异步操作setTimeout
  4. 继承接口,设置所有的生命周期钩子,并打印信息

我们将使用这个组件,来监视组件生命周期。

使用指令控制组件

我们将我们的组件渲染出来,并用我们编写的结构指令“myunless”去实例化和注销这个组件

app/app.ts

import {Component} from 'angular2/core';
import {bootstrap} from 'angular2/platform/browser';
import {UnlessDirective}from './unless.directive';
import {Lifecycle} from './lifecycle'

@Component({
    selector: "app",
    directives:[UnlessDirective,Lifecycle],
    template: `
      <button
      (click)="condition = !condition"
      [style.background] = "condition ? 'orangered': 'lightgreen'"
      >
      Set 'condition' to {{condition ? 'False': 'True'}}
      </button>

      <lifecycle *myUnless="condition" name="lewis"></lifecycle>
    `
})
export class App {
    constructor() {}
}

bootstrap(App, [])
    .catch(err => console.error(err));    

这段代码我们干了这些事:

  1. 注入组件和指令directives:[UnlessDirective,Lifecycle]
  2. 渲染一个button控制成员变量condition的正负
  3. 渲染我们的组件lifecycle,并使用指令控制它的实例化和注销<lifecycle *myUnless="condition" name="lewis"></lifecycle>
  4. 最后启动这个app组件bootstrap(App, []) .catch(err => console.error(err));

开始测试

刷新页面:

  1. onInit是在组件第一次ngOnChanges时执行
  2. OnChanges在input和output绑定的值变化时候;我们可以看到打印了变化的值。可以替代ng1中的$watch;
  3. AfterContentInit、AfterViewInit分别代表在组件内容和视图初始化后执行。
  4. AfterContentChecked和AfterViewChecked是在组件内容和视图检查完后执行。

这里没有DoCheck,因为接口没有证实。

点击Set 'condition' toTrue按钮,页面上的组件被注销

console打印:

点击Set 'condition' to False按钮,页面上的组件重新被实例化:

console打印:

打印了一次Onchanges、onInit、AfterContentInit、AfterViewInit、AfterContentChecked和AfterViewChecked,说明组件实例化,只需要触发一轮初始化和变化检查。与刷新页面的五次对比,我们可以知道多余的“变化检查”,可能来源于angualr的启动。

点击click and watch the lifecycle按钮,一秒后页面上的name变为susan:

console打印

先打印一次AfterContentChecked和AfterViewChecked,一秒后又打印两次。OnChanges没有触发。

结论和收获

  1. TemplateRef, ViewContainerRef这两个服务可以帮助我们实现结构指令的编写
  2. 结构指令可以完全注销组件,节约性能消耗
  3. 组件实例化,只需要触发一轮初始化和“变化检查”
  4. angualr的启动会触发多次“变化检查”
  5. 我们可以继承OnChanges接口,来实现类似ng1中的$watch功能,获取变化前后的值,但是只能监视@input装饰的变量
  6. ng2使用zone,将window对象上常见的异步方法(setTimeout等),都打上了“猴子补丁”,使其可以直接更新视图,我们再也不用在异步中写ng1中的$apply了
  7. 我们可以使用setTimeout(()=>{},0),在浏览器的一轮“event loop”后来触发ng2的“变化检查”
  8. 我们触发类的成员函数(doSomething)时,也会导致ng2的“变化检查”

教程源代码及目录

如果您觉得本博客教程帮到了您,就赏颗星吧!

https://github.com/lewis617/angular2-tutorial

angular2系列教程(五)Structural directives、再谈组件生命周期的更多相关文章

  1. Fastify 系列教程三 (验证、序列化和生命周期)

    Fastify 系列教程: Fastify 系列教程一 (路由和日志) Fastify 系列教程二 (中间件.钩子函数和装饰器) Fastify 系列教程三 (验证.序列化和生命周期) 验证 Fast ...

  2. angular2系列教程(十)两种启动方法、两个路由服务、引用类型和单例模式的妙用

    今天我们要讲的是ng2的路由系统. 例子

  3. CRL快速开发框架系列教程五(使用缓存)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  4. C#微信公众号开发系列教程五(接收事件推送与消息排重)

    微信公众号开发系列教程一(调试环境部署) 微信公众号开发系列教程一(调试环境部署续:vs远程调试) C#微信公众号开发系列教程二(新手接入指南) C#微信公众号开发系列教程三(消息体签名及加解密) C ...

  5. NGUI系列教程五(角色信息跟随)

    在一些网络游戏中,我们常常可以看到角色的上方显示着角色的名称,等级,血量等信息.它们可以跟随角色移动,并且可以显示和隐藏.今天我们就来学习一下这些功能的实现方法.1. 新建unity工 程,导入NGU ...

  6. angular2系列教程(一)hello world

    今天我们要讲的是angular2系列教程的第一篇,主要是学习angular2的运行,以及感受angular2的components以及模板语法. 例子 这个例子非常简单,是个双向数据绑定.我使用了官网 ...

  7. Android Studio系列教程五--Gradle命令详解与导入第三方包

    Android Studio系列教程五--Gradle命令详解与导入第三方包 2015 年 01 月 05 日 DevTools 本文为个人原创,欢迎转载,但请务必在明显位置注明出处!http://s ...

  8. 黄聪:Microsoft Enterprise Library 5.0 系列教程(五) Data Access Application Block

    原文:黄聪:Microsoft Enterprise Library 5.0 系列教程(五) Data Access Application Block 企业库数据库访问模块通过抽象工厂模式,允许用户 ...

  9. Android系列之Fragment(二)----Fragment的生命周期和返回栈

    ​[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/ ...

随机推荐

  1. Apache执行Python脚本

    由于经常需要到服务器上执行些命令,有些命令懒得敲,就准备写点脚本直接浏览器调用就好了,比如这样: 因为线上有现成的Apache,就直接放它里面了,当然访问安全要设置,我似乎别的随笔里写了安全问题,这里 ...

  2. 聊聊Unity项目管理的那些事:Git-flow和Unity

    0x00 前言 目前所在的团队实行敏捷开发已经有了一段时间了.敏捷开发中重要的一个话题便是如何对项目进行恰当的版本管理.项目从最初使用svn到之后的Git One Track策略再到现在的GitFlo ...

  3. 通俗易懂的来讲讲DOM

    DOM是所有前端开发每天打交道的东西,但是随着jQuery等库的出现,大大简化了DOM操作,导致大家慢慢的“遗忘”了它的本来面貌.不过,要想深入学习前端知识,对DOM的了解是不可或缺的,所以本文力图系 ...

  4. jQuery学习之路(3)- 事件

    ▓▓▓▓▓▓ 大致介绍 jQuery增加了并扩展了基本的事件处理机制,不但提供了更加优雅的事件处理语法,而且极大地增强了事件处理能力 ▓▓▓▓▓▓ jQuery中的事件 ▓▓▓▓▓▓ 加载DOM 在j ...

  5. Oracle碎碎念~2

    1. 如何查看表的列名及类型 SQL> select column_name,data_type,data_length from all_tab_columns where owner='SC ...

  6. Redis百亿级Key存储方案(转)

    1 需求背景 该应用场景为DMP缓存存储需求,DMP需要管理非常多的第三方id数据,其中包括各媒体cookie与自身cookie(以下统称supperid)的mapping关系,还包括了supperi ...

  7. Swift enum(枚举)使用范例

    //: Playground - noun: a place where people can play import UIKit var str = "Hello, playground& ...

  8. Activity之概览屏幕(Overview Screen)

    概览屏幕 概览屏幕(也称为最新动态屏幕.最近任务列表或最近使用的应用)是一个系统级别 UI,其中列出了最近访问过的 Activity 和任务. 用户可以浏览该列表并选择要恢复的任务,也可以通过滑动清除 ...

  9. exp/imp 与 expdp/impdp 区别

    在平常备库和数据库迁移的时候,当遇到大的数据库的时候在用exp的时候往往是需要好几个小时,耗费大量时间.oracle10g以后可以用expdp来导出数据库花费的时间要远小于exp花费的时间,而且文件也 ...

  10. VPN连接常见错误汇总

    提示远程服务器没有响应. 这种情况有两种情况,一种是远程服务器出现故障.另一种是自己的电脑出现问题,具体原因我还没有找到,但是可以肯定的是注册表除了问题,一个终极的解决办法就是把注册表替换了.先将HK ...