loading...

Angular2内容分享

TypeScript

  • 为什么要使用TypeScript
  • TypeScript是什么
  • TypeScript的优势
  • 例子

为什么要使用TypeScript

  • 编写很大的JavaScript应用往往不是那么容易

JavaScript程序往往在很大型的应用中组织起来会遇到很多麻烦。

  • 只有JavaScript是不够的

JavaScript没有类型检查。

  • JavaScript版本众多且混乱

现在的JavaScript出现了ES5、ES6、ES7并行的情况,很难抉择。


TypeScript是什么

  • TypeScript是JavaScript的一个类型超集,它会编译为纯JavaScript。

TypeScript和JavaScript的关系

  • 它是开源的,且支持任何浏览器,任何主机和任何操作系统。

TypeScript的优势

  • 静态类型检查
  • 智能感知编译错误
  • 可以立即使用未来的JavaScript功能(ES6、ES7)

例子

代码主要功能:传入一些邮件地址,并对邮件地址进行一些检查。

Object.defineProperty(window, "MySweetApp", { value: "v1.0.0", readonly: false });

function deliveryMethod() {
    // TODO
    return "overnight";
}

function shipWeight(){
    return parseInt(document.getElementById('weight'));
}

/*
 * @param {(string | string[])} emailAddr - An email address of array of email addresses
 */
function sendUpdates(emailAddr) {
    function sendEmail(addr){
        // Default to standard delivery if empty
        console.log(`Shipping to ${addr} via ${deliveryMethod() | "standard"} delivery`);

        if (shipWeight > 100){
            console.log("WARNING: Oversize package");
        }
    }
    // If it's an array, loop over it
    if (emailAddr.length) {
        emailAddr.forEach((idx, val) => {
            sendEmail(val.trim());
        });
    } else {
        sendEmail(emailAddr.trim());
    }
}

这段JavaScript在以.js结尾时不会报任何错误,但当我们将文件名改成.ts之后会发现很多报错。
让我们逐一改掉它们。

JavaScript IS TypeScript

TypeScript的出发点是让JavaScript有更良好的体验,你所知道的JavaScript知识完全可以运用到TypeScript中

实时类型检查

  • 管理JavaScript中最容易出错的可空类型
  • 不可空类型提供“null/undefined”检查

实时类型检查可以很大程度上避免JavaScript中常见的undefined错误。

示例

猜一下代码的每一个分支中的s是什么类型

function test(s : string | string[] | null | undefined) {
    if (s) {
        s; //1
    } else {
        s; //2
    }
    if (s == undefined) {
        s; //3
    } else {
        s; //4
    }
}

添加第三方TypeScript

  • 绝大多数流行的库都有.d.ts类型定义文件
  • 2.0开始不需要任何第三方工具,只需要npm
 npm install -S @types/lodash

TypeScript编辑器支持

总结

  • 使用TypeScript比以前更容易
  • TypeScript和Angular搭配使用体验很棒
  • TypeScript充满未来

Angular2

以下是根据Google开发者大会(GDD)的PPT和官方英雄指南教程总结的Angular2的简介,也是我入门Angular2的过程,分享给大家。
代码已放到Github

  • 组件架构
    • 客户端组件
      • 属性(property)绑定及事件绑定
      • 指令
    • 服务组件
  • 依赖注入
  • 路由

组件架构

Angular 应用是由组件组成的。
组件由 HTML 模板和组件类组成,通过组件类控制视图

客户端组件

相当于View视图

属性(property)绑定及事件绑定

属性绑定

当要把视图元素的属性 (property) 设置为模板表达式时,就要写模板的属性 (property) 绑定。

<li *ngFor="let hero of heroes" [class.selected]="hero === selectedHero">
        <span class="badge">{{hero.id}}</span> {{hero.name}}
</li>
事件绑定

可以使用 Angular 事件绑定机制来响应任何 DOM 事件。 许多 DOM 事件是由用户输入触发的。绑定这些事件可以获取用户输入。
要绑定 DOM 事件,只要把 DOM 事件的名字包裹在圆括号中,然后用放在引号中的模板语句对它赋值就可以了。

<li *ngFor="let hero of heroes" (click)="onSelect(hero)">
  <span class="badge">{{hero.id}}</span> {{hero.name}}
</li>
双向绑定

Angular可以双向数据绑定,如我们在<input>中修改某人的名字时,可以再所有绑定这个人名字的地方看到这些修改。
在我们让表单输入支持双向数据绑定之前,需要先导入FormsModule模块

<input [(ngModel)]="currentHero.firstName">

指令

组件

组件其实就是一个带模板的指令。 它是这三种指令中最常用的,我们会写大量的组件来构建应用程序。

@Component({
  selector: 'my-app',
  // 更新@Component装饰器中指定的模板,为这些新属性建立数据绑定 label input组合可编辑英雄的名字
  template: `
  <h1>{{title}}</h1>
  <h2>My Heroes</h2>
  <ul class="heroes">
    <li>
      <!-- each hero goes here -->
    </li>
  </ul>
  <h2>{{hero.name}} details!</h2>
  <div><label>id: </label>{{hero.id}}</div>
  <div>
    <label>name: </label>
    <input [(ngModel)]="hero.name" value="{{hero.name}}" placeholder="name">
  </div>
  `
})
结构指令

通过添加和移除 DOM 元素改变 DOM 布局的指令如NgForNgIf

<li *ngFor="let hero of heroes">
  <span class="badge">{{hero.id}}</span> {{hero.name}}
</li>
属性指令

属性型指令会修改元素的外观或行为。 比如,内置指令NgStyle就能同时修改元素的好几个样式。 通过绑定到组件的属性,我们可以把文本渲染成加粗、斜体、灰绿色这种肉麻的效果。

<p [style.background]="'lime'">I am green with envy!</p>

服务组件

业务逻辑组件

// 服务的命名规则: 服务名称的小写形式(基本名),加上.service后缀。 如果服务名称包含多个单词,我们就把基本名部分写成中线形式
// (dash-case)。
// 例如,SpecialSuperHeroService服务应该被定义在special-super-hero.service.ts文件中
import {Injectable} from '@angular/core';
// 导入Hero常量
import {Hero} from './hero';
import {HEROES} from './mock-heroes';
// 可注入的服务 我们导入了 Angular 的Injectable函数,并作为@Injectable()装饰器使用这个函数
@Injectable()
export class HeroService {
    // 添加一个getHeros的方法 返回承诺
    getHeroes() : Promise < Hero[] > {
        return Promise.resolve(HEROES);
    } // stub
    //模拟网络延迟
    getHeroesSlowly() : Promise < Hero[] > {
        return new Promise < Hero[] > (resolve => setTimeout(resolve, 2000)) // delay 2 seconds
            .then(() => this.getHeroes());
    }
    getHero(id : number) : Promise < Hero > {
        return Promise.resolve(HEROES.find(hero => hero.id == id));
    }
}

依赖注入

依赖注入是重要的程序设计模式。 Angular 有自己的依赖注入框架,离开了它,几乎没法构建 Angular 应用。
使用@Injectable()装饰器构建可注入的服务

import { Injectable } from '@angular/core';

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

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

在组件中注入并调用这个服务

//引入HeroService服务
import {HeroService} from './hero.service';
//引入OnInit接口
import {OnInit} from '@angular/core';
@Component({
  selector: 'my-app',
  // 更新@Component装饰器中指定的模板,为这些新属性建立数据绑定 label input组合可编辑英雄的名字
  template: `
  <h1>{{title}}</h1>
  <h2>My Heroes</h2>
  <ul class="heroes">
    
    <!-- each hero goes here -->

  `,

  styles: [`
  .selected {
    background-color: #CFD8DC !important;
    color: white;
  }
//......
`],
  // 在Component中创建注入提供商  providers数组告诉
  // Angular,当它创建新的AppComponent组件时,也要创建一个HeroService的新实例。
  providers: [HeroService]

})

//显示我们的英雄
export class AppComponent implements OnInit {
  // 注入HeroService 1、添加一个构造函数,并定义一个私有属性 2、添加组件的providers元数据
  constructor(private heroService : HeroService) {}
  title = 'Tour of Heroes';

  heroes : Hero[];
  // 暴露选中的英雄
  selectedHero : Hero;

  //添加一个从heroService服务中获取英雄的方法 基于承诺 并承诺事情解决再行动
  getHeroes() : void {
    // this.heroes = this   .heroService   .getHeroes();
    this
      .heroService
      .getHeroesSlowly()
      .then(heroes => this.heroes = heroes)
  }
  //实现OnInit接口获取英雄数据
  ngOnInit() : void {
    this.getHeroes();
  }
  //添加一个onSelect方法,用于将用户点击的英雄赋给selectedHero属性
  onSelect(hero : Hero) : void {
    this.selectedHero = hero;
  }
}

路由

浏览器是一个最熟悉的导航模型应用了,输入一个URL地址后浏览器导航相应URL页面,点击网页上的链接导航至另一个新的页面,浏览器的“后退”或“前近”可以导航至我们浏览器的历史页面。

Angular组件路由(也叫路由)就是借用这个模型,可以理解为通过浏览器的网址来生成客户端视图,并通过一些可选参数指定当前显示哪些视图。当然也可以把路由绑定至一个视图组件里,当点击链接时,导航至适合的视图。并且记录在浏览器历史列表,以便浏览器的前进或后退正常工作。

设置页面基本地址

大多数带路由的应用都要在index.html<head>标签下先添加一个<base>元素,来告诉路由器该如何合成导航用的URL。
index.html:

<base href="/">

从路由库中导入

Angular组件路由是个可选组件,所以并不包括在 core 里,需要我们单独引用 @angular/router 模块。
app/app.module.ts

import { RouterModule, Routes } from '@angular/router';

配置路由

app/app.module.ts

const appRoutes: Routes = [
  { path: 'hero/:id', component: HeroDetailComponent },
  { path: 'crisis-center', component: CrisisListComponent },
  {
    path: 'heroes',
    component: HeroListComponent,
    data: {
      title: 'Heroes List'
    }
  },
  { path: '', component: HomeComponent },
  { path: '**', component: PageNotFoundComponent }
];

@NgModule({
  imports: [
    BrowserModule,
    FormsModule,
    RouterModule.forRoot(appRoutes)
  ],
  declarations: [
    AppComponent,
    HeroListComponent,
    HeroDetailComponent,
    CrisisListComponent,
    PageNotFoundComponent
  ],
  bootstrap: [ AppComponent ]
})
export class AppModule {
}

注意:path中不能用斜线/开头

配置路由插座

现在我们已经知道如何配置路由,当浏览器请求URL地址/heroes 时,路由会查找 RouteDefinition 匹配到 HeroListComponent,那么匹配到的组件放在哪呢?我们就需要在当前组件模板里加入 RouterOutlet

    <router-outlet></router-outlet>

路由连接

知道如何配置和显示,那接下来就是如何导航,正常我们是通过浏览器的地址栏输入网站,可大部分是用户去触发某个链接进行导航的。

可以在一个锚标签添加一个 RouterLink 指令,模板表达式绑定的是一个字符串数组类型的网址。

app.component.ts

@Component({
    selector: 'my-app', template: `
    <h1>{{title}}</h1>
    <!--导航-->
    <nav>
     <!--仪表盘-->
     <a routerLink="/dashboard" routerLinkActive="active">Dashboard</a>
     <!--添加锚点标签-->
     <a routerLink="/heroes" routerLinkActive="active">Heroes</a>
    </nav>
    
    <!--添加路由插座-->
    <router-outlet></router-outlet>
  `})

路由总结

先通过 @RouterConfig 配置组件 AppComponent 的路由,再利用 RouterOutlet 来指定命中路由在哪显示,最后使用 RouterLinks 来处理用户点击链接的导航。

Angular 2 VS. React

  • Angular 2 优势
  • React 优势

Angular 2 优势

少一些选择疲劳

Angular提供了更多现成的思路,可以帮助你快速入门而不用为选择库感到恐惧。这种强制一致性也帮助新员工快速入门并使得开发者在团队之间的切换更高效。

而 React,你通常需要加入许多现成的库才能构建一个真正的应用。比如路由库、执行单向流库、webAPI 调用库、测试库、依赖管理库等等。

对初学者友好

跟着官网的指南编写就可以掌握大部分Angular 2的知识,写完基本就可以直接用到项目中。

不同于React,Angular2使用标准html+css,react推荐使用css in js。

标准css

css in js

React 优势

React 以 JavaScript 为中心

这是 React 和 Angular 之间的本质区别。 Angular 2 依然保留以 HTML 为中心而不是以 JavaScript 为中心。

<ul>
  <li *ngFor="#hero of heroes"
    {{hero.name}}
  </li>
</ul>

此代码使用*ngFor属性为HTML添加循环,然而因为js原生支持循环,React 的 JSX 可以简单地利用所有的 JS 能力来处理这些事。

<ul>
  { heroes.map(hero =>
    <li>{hero.name}</li>
  )};
</ul>

Angular 2 奇怪的语法也沿用在 click 绑定:

(click)=”onSelect(hero)"

相反,React 再一次使用了普通的 JavaScript 语法:

onClick={this.onSelect.bind(this, hero)}

在 Angular 和 React 之间做选择就像选择买一个现成的电脑与选择利用现成的部件组装你自己的电脑。

Thank You.