首页 > 代码库 > angular2自学笔记---官网项目(一)

angular2自学笔记---官网项目(一)


1.单向数据绑定的‘插值表达式’

angular中最典型的数据显示方式:把HTML模板(template)的控件绑定到angular组件的属性(component相当于一个构造函数,下面例子中的这个构造函数有name、title、和hero三个属性)
简单来说就是把组件的属性名放到显示曾{{属性名}}中,angular负责喷到页面中;angular从组件中提取属性插入浏览器,然后angular会自动监听这些属性值的变化,一旦属性值发生变化,angular会自动刷新显示,这里的刷新,严格意义上指的是视图事件发生之后,比如定时器运行等

注意:这里模板(template)使用的是ES6的多行字符串的语法,是一个反单引号,就是键盘数字1前面的那个~下面的符号,具体使用可以参照我博客园ES6新增语法中的内容

变量赋值的方法:

import { Component } from @angular/core;

@Component({
  selector: my-app,
  template: `<h1>{{title}}</h1><h2>{{hero}} details!</h2>`,
})
export class AppComponent  {
  name = Angular;
  title=Tour of Heroes;
  hero=Windstorm;
}

输出
Tour of Heroes

Windstorm details!
-------------------------------------------------
同样,和angular1相同,这里模板可以使用template来指定内联的HTML模板片段,也可以使用templateUrl来指定外联的HTML文件(这个HTML外联文件的中的内容只是你需要渲染进页面的一本分HTML片段,templateUrl的值是一个相对路径)

相同的,也可以使用构造函数声明和初始化属性

构造函数声明方法

import { Component } from @angular/core;

@Component({
  selector: my-app,
  template: `
            <h1>{{title}}</h1>
            <h2>My favorite hero is :{{hero}}</h2>
            `
})
export class AppComponent  {
  title:string;
  hero:string;

  constructor(){
    this.title=Tour of Heroes;
    this.hero=Windstrom;
  }
}

注意title:string;使用的是typescript的语法,表明定义变量,这个变量的值必须为string数据类型

2.ngFor显示属性(angular的迭代指令):*ngFor

import { Component } from @angular/core;

@Component({
  selector: my-app,
  template: `
            <h1>{{title}}</h1>
            <h2>My favorite hero is :{{myHero}}</h2>
            <p>Heros:</p>
            <ul>
              <li *ngFor="let hero of heros">{{hero}}</li>
            </ul>
            `
})
export class AppComponent  {
  title=Tour of Heroes;
  heros=[Windstrom,Jason,andy];
  myHero=this.heros[0]
}

*ngFor=‘let hero of heros‘ 中的hero是一个模板输入变量 相当于 name in item
简单的说上述例子中的模板中的li可以换成<li *ngFor="let name of heros">{{name}}</li>

浏览器中的渲染结果如下
Tour of Heroes

My favorite hero is :Windstrom

Heros:

Windstrom
Jason
andy

为数据创建一个类

export class Hero{
constructor(public id:number, public name:string){

}
}
这里使用了ES6和TS的语法:创建了一个类Hero,这个类是一个构造函数,他有两个属性,一个是number类型值的属性id和一个是string类型属性的name,当我们new出这个实例的时候,这些属性将会初始化相应的参数

下面来使用这个Hero类(注意先后顺序,使用模板之前需要定义对象)

import { Component } from @angular/core;

export class Hero{
  constructor(public id:number, public name:string){

  }
}

@Component({
  selector: my-app,
  template: `
            <h1>{{title}}</h1>
            <h2>My favorite hero is :{{myHero.name}}</h2>
            <p>Heros:</p>
            <ul>
              <li *ngFor="let hero of heros">{{hero.name}}</li>
            </ul>
            `
})
export class AppComponent  {
  title=Tour of Heroes;
  heros=[
    new Hero(1,Jason),
    new Hero(2,andy),
    new Hero(3,windStrom)
  ];
  myHero=this.heros[0]
}


3.ngIf:根据一个布尔值来进行显示或移除一个元素,注意是DOM操作,增或者删

<p *ngIf="heros.length>3">There are many heros!</p>

这个的意思表示如果heros的length大于3就创建一个p标签,反之,不成立就是false就移除这个p标签,注意ngIf中添加的只能是真假


4.双向数据绑定
需要使用 FormsModule模块,并且需要把它添加到NgModule装饰器的imports数组中,该数组是如果是外部模块,则需要引入,引入的方式就是上面第一句话:

import {FormsModule} from @angular/forms;

app.module.ts文件
import { NgModule }      from @angular/core;
import { BrowserModule } from @angular/platform-browser;
import {FormsModule} from @angular/forms;

import { AppComponent }  from ./app.component;

@NgModule({
  //入口模块
  imports: [BrowserModule,FormsModule],
  //生命文件
  declarations:[AppComponent,HeroDetailComponent],
  //引导程序
  bootstrap:[AppComponent]
})
export class AppModule { }
export class AppModule { }


app.component.ts文件中修改input标签的双向绑定为
<input type="text" value="" [(ngModel)]="heros.name" placeholder="name">


5.定义一个数组

export class Hero{
  constructor(public id:number, public name:string){

  }
}

const HEROES:Hero[]=[
  {id:1,name:Jason},
  {id:2,name:xuekui},
  {id:3,name:xiaoming},
  {id:4,name:xiaohong},
  {id:5,name:xiaoli},
  {id:6,name:blue},
  {id:7,name:green},
  {id:8,name:orage},
  {id:9,name:yellow},
  {id:10,name:red},
];

Hero是一个数组的构造函数,HEROES是一个实例化的数组

暴漏数组(创建一个公共属性,供绑定使用):heroes=HEROS; 这里没有明确heros属性的数据类型,TS有很强的隐式类型声明系统(类型推测)

创建数组并循环喷入页面

import { Component } from @angular/core;

export class Hero{
  constructor(public id:number, public name:string){

  }
}

const HEROES:Hero[]=[
  {id:1,name:Jason},
  {id:2,name:xuekui},
  {id:3,name:xiaoming},
  {id:4,name:xiaohong},
  {id:5,name:xiaoli},
  {id:6,name:blue},
  {id:7,name:green},
  {id:8,name:orage},
  {id:9,name:yellow},
  {id:10,name:red}
];

@Component({
  selector: my-app,
  template: `
            <h1>{{title}}</h1>
            <h2>My Heroes</h2>
            <ul>
              <li *ngFor="let hero of Heroes">
                <!--each hero goes here-->
                <span class="badge">{{hero.id}}</span>{{hero.name}}
              </li>
            </ul>
            `
})
export class AppComponent  {
  title=Tour of Heroes;
  Heroes=HEROES;
}


7.为一个组件设置内联样式

在@Component装饰器的styles属性设置css类:使用ES6的反引号语法书写多行字符串,注意,为一个组件指定样式时,他们的作用域将仅限于该组件,不会泄露到外部HTML中。

styles: [`
  .selected {
    background-color: #CFD8DC !important;
    color: white;
  }
  .heroes {
    margin: 0 0 2em 0;
    list-style-type: none;
    padding: 0;
    width: 15em;
  }
  .heroes li {
    cursor: pointer;
    position: relative;
    left: 0;
    background-color: #EEE;
    margin: .5em;
    padding: .3em 0;
    height: 1.6em;
    border-radius: 4px;
  }
  .heroes li.selected:hover {
    background-color: #BBD8DC !important;
    color: white;
  }
  .heroes li:hover {
    color: #607D8B;
    background-color: #DDD;
    left: .1em;
  }
  .heroes .text {
    position: relative;
    top: -3px;
  }
  .heroes .badge {
    display: inline-block;
    font-size: small;
    color: white;
    padding: 0.8em 0.7em 0 0.7em;
    background-color: #607D8B;
    line-height: 1em;
    position: relative;
    left: -1px;
    top: -4px;
    height: 1.8em;
    margin-right: .8em;
    border-radius: 4px 0 0 4px;
  }
`]

8.主从结构:主视图---列表视图,从视图---被选中的结构的详细信息视图

点击事件 (click)="函数名(参数)" 在点击事件上绑定属性链接主从视图

[class.selected]="hero === selectedHero" 类名的选择,当引号中为true的时候,类名添加,当引号中为false的时候,类名去除。


9.命名规范:我们的所有组件名都以Component结尾。所有组件的文件名都以.component结尾。

这里我们使用小写中线命名法 (也叫烤串命名法)拼写文件名, 所以不用担心它在服务器或者版本控制系统中出现大小写问题。
我们使用@Component装饰器创建元数据。在元数据中,我们指定选择器的名字,用以标识此组件的元素。 然后,我们导出这个类,以便其它组件可以使用它。

引入文件 import语句 : import {导入的函数} form ‘路径‘;

升级AppComponent的模板,把该组件的selectedHero属性绑定到HeroDetailComponent组件的hero属性上。 绑定看起来可能是这样的:

绑定组件: <my-hero-detail [hero]="selectedHero"></my-hero-detail>
注意,hero是属性绑定的目标 — 它位于等号 (=) 左边方括号中。 目标属性就是需要得到的目标属性

Angular 希望我们把目标属性声明为组件的输入属性,否则,Angular 会拒绝绑定,并抛出错误。

10.模块之间的项目引用

@NgModule({
  imports: [BrowserModule,FormsModule],
  declarations:[AppComponent,HeroDetailComponent],
  bootstrap:[AppComponent]
})
export class AppModule { }

declaration这个数组包含了所有创建的并属于应用模块组件、管道和指令。

------------------------------------------------------------
小结:创建一个可复用组件的思路(把父组件绑定到子组件中)

1》新建新的装饰器@Component,在装饰器中使用自定义标签selector:‘标签名‘, 来盛放准备复用的组件
2》在新建的装饰器@Component的模板telplete中编辑复用模板的view视图层,这里的数据是自己组件所特有的
3》在组件中通过前面导入的装饰器向组件中添加注释的方法省输入属性
export class HeroDetailComponent{
@Input()
hero:Hero;
}
4》添加模块之间的项目引用(在angular中生命该应用所需的指令)

        @NgModule({
          imports: [BrowserModule,FormsModule],
          declarations:[AppComponent,HeroDetailComponent],
          bootstrap:[AppComponent]
        })
        export class AppModule { }

5》在需要复用的地方插入自定义标签,并绑定相关数据
注入在双向绑定的时候 属性绑定目标位于等号的左侧,否则angular会拒绝绑定并抛出错误
---------------------------------------------------------------

11.服务

引入服务并且在服务中引入服务数据

import { Injectable } from @angular/core;

import { Hero } from ./hero;
import { HEROES } from ./mock-heroes;

@Injectable()
export class HeroService {
  getHeroes(): Hero[] {
    return HEROES;
  }
}


数据使用者并不知道本服务会如何获取数据。服务可以从任何地方获取英雄的数据。可以从网络服务器获取、从浏览器的局部存储区获取、可以从模拟的数据源获取。

这就是从组件中移除数据访问代码的美妙之处。 这样我们可以随时改变数据访问的实现方式,而无需对使用英雄的组件作任何改动。

//导入想要的东西,比如服务 导入服务后便可以在代码中应用 可以new一个HeroService
import {HeroService} from ‘./hero.service‘;

newnew一个HeroService(服务)的缺点:
1》如果修改了服务代码,则需要修改每一处使用服务的代码
2》new的服务实例不能提供缓存数据列表共享

解决办法:使用providers注入模块依赖(和angular1中注入模块意义相同,angular1中的注入模块能提供constroller之间的相互关联,暂时可以这么理解),构造函数自己什么也不用做,它在参数中定义了一个私有的heroService属性,并把它标记为注入HeroService的靶点。
更多注入依赖示例:http://origin.angular.live/docs/ts/latest/guide/dependency-injection.html

constructor(private heroService: HeroService) { }

使用这行代码钱需要给服务注册一个提供商(HeroService),来表明(告诉注册器)服务的来源指向:
providers: [HeroService]


12.ngOnInit生命周期钩子
更多生命周期钩子:http://origin.angular.live/docs/ts/latest/guide/lifecycle-hooks.html

ngOnInit接口基本的轮廓

    import { OnInit } from @angular/core;

    export class AppComponent implements OnInit {
      ngOnInit(): void {
      }
    }

13.异步服务--承诺 promise
承诺的意思简单来说就是异步:承诺在有结果的时候给一个回调函数,并通过参数把结果传递回来,这个回调promise是ES6语法中的
更过承诺的解释:http://exploringjs.com/es6/ch_promises.html

服务与承诺 Promise<Hero[]>----TS语法中的泛型,泛型有限制,any无限制

export class HeroService {
  getHeroes(): Promise<Hero[]> {
    return Promise.resolve(HEROES);
  }
}

export class HeroService {
  getHeroes(): Promise<Hero[]> {
    return Promise.resolve(HEROES);
  }
}

使用服务的承诺的时候使用承诺对象的then的方法

//导入数据
getHeroes():void{
//需要获得的数据在等号的左面,数据来源在等号的右面 服务中使用了Promise,这里的数据来源也需要使用承诺
//把Promise的回调函数的参数传给承诺对象的箭头函数(then方法)
this.heroService.getHeroes().then(heroes => this.heroes=heroes);
}

更多箭头函数:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions

模拟慢网速连接:http://origin.angular.live/docs/ts/latest/tutorial/toh-pt4.html#!#slow


服务模块的小结:
1》创建共享服务类,引入共享的数据 共享数据的构造函数,输出一个服务,在服务中使用回调函数异步的返回承诺Promise的结果(promise.resolve)
2》使用生命钩子OnInit在主逻辑激活的时候获取这个服务(引入OnInit模块,在输出的时候添加生命钩子的的工具--implement OnInit)
3》提供服务的提供商:在装饰器中添加promises的来源
4》组件从服务中获取数据:把Promise的回调函数的参数传给承诺对象的箭头函数(then方法)


14.路由:angular2的路由是帮你找到另一个组件的;路由是导航的另一个名字。路由器就是从一个视图导航到另一个视图的机制。
更多路由和导航的介绍:http://origin.angular.live/docs/ts/latest/guide/router.html

--------------------------------------------------------
新的AppComponent将成为应用的“壳”。 它将在顶部放一些导航链接,并且把我们要导航到的页面放在下面的显示区中。

这些起始步骤是:

添加支持性的import语句。
创建一个名叫app.component.ts的新文件。
定义一个导出的 AppComponent类。
在类的上方添加@Component元数据装饰器,装饰器带有my-app选择器。
将下面的项目从HeroesComponent移到AppComponent:
title类属性
@Component模板中的<h1>标签,它包含了对title属性的绑定。
在模板的标题下面添加<my-heroes>标签,以便我们仍能看到英雄列表。
添加HeroesComponent组件到根模块的declarations数组中,以便 Angular 能认识<my-heroes>标签。
添加HeroService到AppModule的providers数组中,因为我们的每一个视图都需要它。
从HerosComponent的providers数组中移除HeroService,因为它被提到模块了。
导入AppComponent。
---------------------------------------------------------


Angular 路由器是一个可选的外部 Angular NgModule,名叫RouterModule。 路由器包含了多种服务(RouterModule)、多种指令(RouterOutlet、RouterLink、RouterLinkActive)、 和一套配置(Routes)

路由使用小结:
1》在首页HTML设置base标签:在<head>区的顶部添加<base href="http://www.mamicode.com/">语句。
更多解释:http://origin.angular.live/docs/ts/latest/guide/router-deprecated.html#!#base-href
2》配置路由:将路由放入模块配置@NgModule的入口文件imports数组中

路由告诉路由器,当用户点击链接或者把 URL 粘贴到浏览器地址栏时,应该显示哪个视图。
路由定义包括以下部分:更多定义(http://origin.angular.live/docs/ts/latest/guide/router.html)
path: 路由器会用它来匹配浏览器地址栏中的地址
component: 导航到此路由时,路由器需要创建的组件

forRoot方法:在应用根部提供配置的路由器。 forRoot方法提供了路由需要的路由服务提供商和指令,并基于当前浏览器 URL 初始化导航。
3》路由插座:<router-outlet>,RouterOutlet是RouterModule提供的指令之一。 当我们在应用中导航时,路由器就把激活的组件显示在<router-outlet>里面。

动态路由器连接和*连接参数数组:http://origin.angular.live/docs/ts/latest/guide/router.html#!#link-parameters-array

4》路由重定向:redirectTo
更多路由重定向:http://origin.angular.live/docs/ts/latest/guide/router.html#!#redirect

        {
          path: ‘‘,
          redirectTo: /dashboard,
          pathMatch: full
        }, 

 

这只是我自学的笔记,如果有何错误欢迎大家指正

angular2自学笔记---官网项目(一)