Angular2 入门教程

一、 入门

1、初识Angular2

硬知识:Angular2与Angular的区别

(1)依赖加载:Angular1是依赖前置,angular2是按需加载

(2)数据绑定:

Angular1 在启动时会给所有的异步交互点打补丁:
超时、
Ajax 请求、
浏览器事件、
Websockets,等等
在那些交互点,Angular 会对 scope 对象进行变动检查,如果发现有变动就激发相应的监视器
重新运行变动检查,检查是否有更多的变化发生,重新运行监视器

Angular 2 使用 zone.js 机制使摘要循环不再被需要。简单的非 Angular 指定代码可以透明地激发一个Angular 2 摘要。
zone.js的设计灵感来源于Dart语言,它描述JavaScript执行过程的上下文,可以在异步任务之间进行持久性传递,它类似于Java中的TLS(线程本地存储)技术,zone.js则是将TLS引入到JavaScript语言中的实现框架。

写一个Angular2的Hello World应用相当简单,分三步走:

  1. 引入Angular2预定义类型
import {Component,View,bootstrap} from "angular2/angular2";

import是ES6的关键字,用来从模块中引入类型定义。在这里,我们从angular2模块库中引入了三个类型: Component类、View类和bootstrap函数。

  1. 实现一个Angular2组件

实现一个Angular2组件也很简单,定义一个类,然后给这个类添加注解:

@Component({selector:"ez-app"})
@View({template:"

Hello,Angular2

"
}) class EzApp{}

class也是ES6的关键字,用来定义一个类。@Component和@View都是给类EzApp附加的元信息, 被称为注解/Annotation。

@Component最重要的作用是通过selector属性(值为CSS选择符),指定这个组件渲染到哪个DOM对象上。 @View最重要的作用是通过template属性,指定渲染的模板。

  1. 渲染组件到DOM

将组件渲染到DOM上,需要使用自举/bootstrap函数:

bootstrap(EzApp);

这个函数的作用就是通知Angular2框架将EzApp组件渲染到DOM树上。

2、注解/Annotation

ES6规范里没有装饰器。这其实利用了traceur的一个实验特性:注解。给一个类 加注解,等同于设置这个类的annotations属性:

//注解写法
@Component({selector:"ez-app"})
class EzApp{...}
等同于:

class EzApp{...}
EzApp.annotations = [new Component({selector:"ez-app"})];

很显然,注解可以看做编译器(traceur)层面的语法糖,但和python的装饰器不同, 注解在编译时仅仅被放在annotation里,编译器并不进行解释展开 - 这个解释的工作是 Angular2完成的

二、组件开发–模板语法

1、最简单的模板

有两种方法为组件指定渲染模板:

  1. 内联模板

可以使用组件的View注解中的template属性直接指定内联模板:

@View({
    template : `<h1>helloh1>
                <div>...div>`
})

在ES6中,使用一对`符号就可以定义多行字符串,这使得编写内联的模板轻松多了。

  1. 外部模板

也可以将模板写入一个单独的文件:


<h1>helloh1>
<div>...div>
然后在定义组件时,使用templateUrl引用外部模板:

@View({
    templateUrl : "ezcomp-tpl.html"
})

2、directives - 使用组件

在Angular2中,一个组件的模板内除了可以使用标准的HTML元素,也可以使用自定义的组件!

这是相当重要的特性,意味着Angular2将无偏差地对待标准的HTML元素和你自己定义的组件。这样, 你可以建立自己的领域建模语言了,这使得渲染模板和视图模型的对齐更加容易,也使得模板的语义性 更强:

@Component({selector:"ez-app"})
        @View({
            directives:[EzCard],
            template:`
                
class="ez-app"> <h1>EzApph1> <ez-card>ez-card> div>` }) class EzApp{} @Component({selector : "ez-card"}) @View({ directives:[EzLogo], template : `
class="ez-card"> <h1>EzCardh1> <ez-logo>ez-logo> div>` }) class EzCard{} @Component({selector : "ez-logo"}) @View({ template : `
class="ez-logo"> <h1>EzLogoh1> div>` }) class EzLogo{} bootstrap(EzApp);

声明要在模板中使用的组件

不过,在使用自定义组件之前,必需在组件的ViewAnnotation中通过directives属性声明这个组件:

@View({
    directives : [EzComp],
    template : ""
})

你应该注意到了,directives属性的值是一个数组,这意味着,你需要在这里声明所有你需要在模板 中使用的自定义组件。

3、{{model}} - 文本插值

在模板中使用可以{{表达式}}的方式绑定组件模型中的表达式,当表达式变化时, Angular2将自动更新对应的DOM对象:

import {Component,View,bootstrap} from "angular2/angular2";

        @Component({selector:"ez-app"})
        @View({
            template:`
                <div>
                    <h1>{{title}}h1>
                    <div>
                        <span>{{date}}span> 来源:<span>{{source}}span>
                    div>
                div>
            `
        })
        class EzApp{
            constructor(){
                this.title = "证监会:对恶意做空是有监测的";
                this.date = "2015年07月11日 15:32:35";
                this.source = "北京晚报";
            }
        }

        bootstrap(EzApp);

4、[property] - 绑定属性

在模板中,也可以使用一对中括号将HTML元素或组件的属性绑定到组件模型的某个表达式, 当表达式的值变化时,对应的DOM对象将自动得到更新:

import {bind,Component,View,bootstrap} from "angular2/angular2";

        @Component({selector:"ez-app"})
        @View({
               template:`

"color">Hello,Angular2</h1>` }) class EzApp{ constructor(){ this.color = 'red'; this.d = ["red", "green", "blue", "yellow", "black", "grey"]; var self = this; var num = 0; setInterval(function () { num++; if (num + 1 == self.d.length) { num = 0 } self.color = self.d[num]; }, 500); } } bootstrap(EzApp);

以上的代码,h1标签会每秒自动变颜色。

5、(event) - 监听事件

在模板中为元素添加事件监听很简单,使用一对小括号包裹事件名称,并绑定 到表达式即可:

import {Component,View,bootstrap} from "angular2/angular2";

        @Component({selector:"ez-app"})
        @View({
            template:`  
                

Your turn! {{sb}}

` }) class EzApp{ constructor(){ this.names = ["Jason","Mary","Linda","Lincoln","Albert","Jimmy"]; this.roulette(); } //轮盘赌 roulette(){ var idx = parseInt(Math.random()*this.names.length); this.sb = this.names[idx]; } } bootstrap(EzApp);

上面的代码实例为DOM对象h1的click事件添加监听函数onClick()。

另一种等效的书写方法是在事件名称前加on-前缀:

@View({template : `<h1 on-click="onClick()">HELLOh1>`})

6、#var - 局部变量

有时模板中的不同元素间可能需要互相调用,Angular2提供一种简单的语法将元素 映射为局部变量:添加一个以#或var-开始的属性,后续的部分表示变量名, 这个变量对应元素的实例。

在下面的代码示例中,我们为元素h1定义了一个局部变量v_h1,这个变量指向 该元素对应的DOM对象,你可以在模板中的其他地方调用其方法和属性:

@View({
    template : `
        <h1 #v_h1>helloh1>
        <button (click) = "#v_h1.textContent = 'HELLO'">testbutton>
    `
})

如果在一个组件元素上定义局部变量,那么其对应的对象为组件的实例:

@View({
    directives:[EzCalc],
    template : ""
})

在上面的示例中,模板内的局部变量c指向EzCalc的实例。

三、条件逻辑

1、NgIf

有时我们需要模板的一部分内容在满足一定条件时才显示, NgIf发挥作用的场景,它评估属性ngIf的值是否为真,来决定是否渲染 template元素的内容:

@View({
    template : `
                <template *ngIf="trial==true">
                    <img src="ad.jpg">
                template>
                
                <pre>...
` })

2、ngSwitch

"switch_expression">
  "match_expression_1">...
  "match_expression_2">...
  "match_expression_3">...
  "match_expression_3">
    
    
    
  
  ...

3、ngFor

  • "let item of items; let i = index; trackBy: trackByFn">...
  • "ngFor let item of items; let i = index; trackBy: trackByFn">...
  • NgFor provides several exported values that can be aliased to local variables:

    • index will be set to the current loop iteration for each template context.
    • first will be set to a boolean value indicating whether the item is the first one in the iteration.
    • last will be set to a boolean value indicating whether the item is the last one in the iteration.
    • even will be set to a boolean value indicating whether this item has an even index.
    • odd will be set to a boolean value indicating whether this item has an odd index.

    四、属性与事件声明

    1、属性声明–暴露成员变量

    属性是组件暴露给外部世界的调用接口,调用者通过设置不同的属性值来定制 组件的行为与外观:

    Angular2 入门教程_第1张图片

    在Angular2中为组件增加属性接口非常简单,只需要在Component注解的 properties属性中声明组件的成员变量就可以了:

    //EzCard 
    @Component({
        properties:["name","country"]
    })

    上面的代码将组件的成员变量name和country暴露为同名属性,这意味着在EzApp 的模板中,可以直接使用中括号语法来设置EzCard对象的属性:

    //EzApp
    @View({
        directives : [EzCard],
        template : "'雷锋'" [country]="'中国'">"
    })

    提醒:如果要在模板中使用自定义的指令(组件是一种指令),必须在View注解的directives 属性中提前声明!

    示例代码:为EzCard调用添加name和country属性!

    import {Component,View,bootstrap} from "angular2/angular2";
    
            //根组件 - EzApp
            @Component({selector:"ez-app"})
            @View({
                directives:[EzCard],
                template:`
                    
    class="ez-app">

    EzApp

    "'frank'" [country]="'China'">
    ` }) class EzApp{} //具有属性接口的组件 - EzCard @Component({ selector:"ez-card", properties:["name","country"] }) @View({ template : `
    class='ez-card'> My name is {{name}}, I am from {{country}}.
    ` }) class EzCard{ constructor(){ this.name = "Mike"; this.country = "Sweden"; } } //渲染组件 bootstrap(EzApp);

    2、事件声明 - 暴露事件源

    与属性相反,事件从组件的内部流出,用来通知外部世界发生了一些事情:
    Angular2 入门教程_第2张图片

    在Angular2中为组件增加事件接口也非常简单:定义一个事件源/EventEmitter, 然后通过Component注解的events接口包括出来:

    //EzCard
    @Component({
        events:["change"]
    })
    class EzCard{
        constructor(){
            this.change = new EventEmitter();
        }
    }

    上面的代码将组件EzCard的事件源change暴露为同名事件,这意味着在调用者 EzApp组件的模板中,可以直接使用小括号语法挂接事件监听函数:

    //EzApp
    @View({
        template : "">"
    })

    每次EzCard触发change事件时,EzApp的onChange()方法都将被调用。

    import {Component,View,bootstrap,EventEmitter} from "angular2/angular2";
    
            //根组件 - EzApp
            @Component({selector:"ez-app"})
            @View({
                directives:[EzCard],
                template:`
                    
    class="ez-app"> <h1>EzApph1> <ez-card (change)="onChange($event)">ez-card> <pre>{{evtStr}}pre> div>` }) class EzApp{ constructor(){ this.evtStr } onChange(evt){ console.log("sth. occured"); this.evtStr = JSON.stringify(evt,null,"\t"); } } //具有事件接口的组件 - EzCard @Component({ selector:"ez-card", events:["change"] }) @View({ template : `
    class='ez-card'> My name is {{name}}</b>, I am from {{country}}b>.</div>` }) class EzCard{ constructor(){ this.name = "Mike"; this.country = "Sweden"; this.change = new EventEmitter(); //模拟触发事件 setTimeout(()=>this.change.next({ src:"EzCard", desc:"模拟事件" }),1000); } } //渲染组件 bootstrap(EzApp);

    五、form

    1、NgForm - 表单指令

    NgForm指令为表单元素/form建立一个控件组对象,作为控件的容器; 而NgControlName指令为则为宿主input元素建立一个控件对象,并将该控件加入到NgForm 指令建立的控件组中:

    Angular2 入门教程_第3张图片

    局部变量

    通过使用#符号,我们创建了一个引用控件组对象(注意,不是form元素!)的局部变量f。 这个变量最大的作用是:它的value属性是一个简单的JSON对象,键对应于input元素的 ng-control属性,值对应于input元素的值:

    Angular2 入门教程_第4张图片

    声明指令依赖

    NgForm指令和NgControlName指令都包含在预定义的数组变量formDirectives中,所以我们在 组件注解的directives属性中直接声明formDirectives就可以在模板中直接使用这些指令了:

    //angular2/ts/src/forms/directives.ts
    export const formDirectives = CONST_EXPR([
      NgControlName,
      NgControlGroup,
    
      NgFormControl,
      NgModel,
      NgFormModel,
      NgForm,
    
      NgSelectOption,
      DefaultValueAccessor,
      CheckboxControlValueAccessor,
      SelectControlValueAccessor,
    
      NgRequiredValidator
    ]);

    为示例代码中的select元素也使用NgControlName指令,并在反馈中显示所选择 的搜索类别!

    import {Component,View,bootstrap,NgIf} from "angular2/angular2";
            //引入form指令集
            import {formDirectives} from "angular2/forms";
    
            //EzApp组件
            @Component({selector:"ez-app"})
            @View({
                directives:[formDirectives,NgIf],
                template:`
                    <form #f="form" (submit)="search(f.value)">
                        <select ng-control="kw2">
                            <option selected value="web">网页option>
                            <option value="news">新闻option>
                            <option value="image">图片option>
                        select>
                        <input type="text" ng-control="kw">
                        <button type="submit">搜索button>
                    form>
                    
                    <h1 *ng-if="kw!=''">正在搜索 {{kw}} {{kw2}}h1>
                `,
                styles:[`form{background:#90a4ae;padding:5px;}`]            
            })
            class EzApp{
                constructor(){
                    this.kw = "";
                    this.kw2="";
                }
                search(val){
                    this.kw = val.kw;
                    this.kw2 = val.kw2;
                    //假装在搜索,2秒钟返回
                    setTimeout(()=>this.kw="",2000);
                }
            }
    
    
    
            bootstrap(EzApp);

    2、NgControlName - 命名控件指令

    如前所述,NgControlName指令必须作为NgForm或NgFormModel的后代使用, 因为这个指令需要将创建的控件对象添加到祖先(NgForm或NgFormModel)所创建 的控件组中。

    NgControlName指令的选择符是[ng-control],这意味着你必须在一个HTML元素上 定义ng-control属性,这个指令才会起作用。

    属性:ngControl

    NgControlName指令为宿主的DOM对象创建一个控件对象,并将这个对象以ngControl属性 指定的名称绑定到DOM对象上:

    <form #f="form">
        <input type="text" ng-control="user">
        <input type="password" ng-control="pass">
    </form>

    在上面的代码中,将创建两个Control对象,名称分别为user和pass。

    属性/方法:ngModel

    除了使用控件组获得输入值,NgControlName指令可以通过ngModel实现模型 与表单的双向绑定:

    <form>
        <input type="text" ng-control="user" [(ng-model)]="data.user">
        <input type="password" ng-control="pass" [(ng-model)]="data.pass">
    form>`

    ngModel即是NgControlName指令的属性,也是它的事件,所以下面 的两种写法是等价的:

    type="text" ng-control="user" [(ng-model)]="data.user">
    //等价于
    type="text" ng-control="user" [ng-model]="data.user" (ng-model)="data.user">

    3、NgCongrolGroup - 命名控件组

    NgControlGroup指令的选择符是[ng-control-group],如果模板中的某个元素具有这个属性, Angular2框架将自动创建一个控件组对象,并将这个对象以指定的名称与DOM对象绑定。

    控件组可以嵌套,方便我们在语义上区分不同性质的输入:

    Angular2 入门教程_第5张图片

    和NgControlName指令一样,NgControlGroup指令也必须作为NgForm或NgFormModel的 后代使用,因为这个指令需要将创建的控件组对象添加到祖先(NgForm或NgFormModel)所创建 的控件组中。

    
        

    输出结果:

    {
        "basic": {
            "name": "123",
            "address": "123",
            "telephone": "123"
        },
        "expertise": {
            "english": true,
            "tech": true,
            "sport": true
        }
    }

    4、NgFormControl - 绑定已有控件对象

    与NgControlName指令不同,NgFormControl将已有的控件/Control对象绑定到DOM元素 上。当需要对输入的值进行==初始化==时,可以使用NgFormControl指令。

    下面的代码中,使用NgFormControl指令将DOM元素绑定到组件EzComp的成员 变量movie上,我们需要在构造函数中先创建这个Control对象:

    @View({
        //将输入元素绑定到已经创建的控件对象上
        template : `type="text" [ng-form-control]="movie">`
    })
    class EzComp{
        constructor(){
            //创建控件对象
            this.movie = new Control("Matrix II - Reload");
        }
    }

    控件/Control是Angular2中对表单输入元素的抽象,我们使用其value属性,就可以获得对应的 输入元素的值。

    与NgControlName指令的另一个区别是,NgFormControl不需要NgForm或NgFormModel的祖先。

    
        

    5、NgFormModel - 绑定已有控件组

    NgFormModel指令类似于NgControlGroup指令,都是为控件提供容器。但区别在于, NgFormModel指令将已有的控件组绑定到DOM对象上:

    @View({
        template : `
            
            <div [ng-form-model]="controls">
                <input type="text" ng-control="name">
                <input type="text" ng-control="age">
            div>`
    })
    class EzComp{
        constructor(){
            //创建控件组及控件对象
            this.controls = new ControlGroup({
                name :new Control("Jason"),
                age : new Control("45")
            });
        }
    }

    NgFormModel指令可以包含NgControlGroup指令,以便将不同性质的输入分组。

    六、 @input和@output

    先做个比方,然后奉上代码比如:

    "someExp" (rate)="eventHandler($event.rating)">

    input:
    [talk]=”someExp” 这个标签可以理解为一个专门的监听器,监听父组件传递过来的someExp参数,并存入自身组件的talk变;好像是开了个后门,允许且只允许父组件的someExp进入,一旦进入立刻抓进一个叫talk的牢房,然后==子组件==中就可以通过@Input来定义这个变量talk然后使用它。

    output:
    (rate)=”eventHandler(event.rating) 这个意思是, 当子组件的click事件被触发,就执行父组件的eventHandler函数,并把子组件的参数 event.rating传递给父组件的eventHandler函数;就好像,当小孩子一哭(执行click事件),他的母亲立刻把他抱在怀里(执行母亲的eventHandler),同时母亲获得了小孩子的一些参数(event.rating)

    1、@input()

    父组件 father.component.ts 提供数据

    import {Component} from "@angular/core";
    @Component({
        selector: "my-father",
        templateUrl: "father.html"
    })
    export class FatherComponent {
        data: Array;
        constructor() {
            this.data = [
                {
                    "id": 1,
                    "name": "html"
                },
                {
                    "id": 2,
                    "name": "css"
                },
                {
                    "id": 3,
                    "name": "angular"
                },
                {
                    "id": 4,
                    "name": "ionic"
                },
                {
                    "id": 5,
                    "name": "node"
                }
            ]
        }
    } 
      

    模板文件 father.html

    <h1>父组件h1>
    // 包含子组件, 并使用属性传递数据过去
    <my-child [info]="data">my-child>

    子组件 child.component.ts 获取数据

    import {Component, Input} from "@angular/core";
    @Component({
        selector: "my-child",
        templateUrl: "child.html"
    })
    export class ChildComponent {   
        // 使用@Input获取传递过来的数据
        @Input()
        info: Array;
        constructor() {
    
        }
    } 
      

    子组件 child.html模板文件

    <ul>
        <li *ngFor="let item of info">
            {{item.name}}
        li>
    ul>

    2、@Output()

    子组件three-link.component.ts

    1. 引入
    import {Component, OnInit, Output, EventEmitter} from "@angular/core";
    1. 定义输出变量
    export class ThreeLinkComponent {
        province: string;
        // 输出一下参数
        @Output() provinceOut = new EventEmitter();   
        constructor() {
            this.province = "陕西";
        } 
    }
    1. 事件出发,发射变量给父组件
    provinceChange() {
        // 选择省份的时候发射省份给父组件
        this.provinceOut.emit(this.province);
    }

    父组件模板

    
    <three-link (provinceOut)="recPro($event)">three-link>

    父组件

    // 函数接受子函数传递过来的变量, 子函数中emit的时候触发这个函数。

    recPro(event) {
       this.province = event;
    }

    你可能感兴趣的:(angular2-0)