Angular2 初探

jopen 8年前發布 | 83K 次閱讀 Angular2 Web框架 angularjs

Angular2初探

盼星星盼月亮終于把angular2 beta盼來了,在beta前一個月快一天一個release都把小G折磨壞了,小G公司用的angular2,然后就跟著Google那些工程師一天一個update,然后還要看update把以前的啥功能break了沒,當時改rxjs的api的時候真的是想死的心都有了。還有rxjs帶來的各種 bug,終于迎來了angular2 beta,碼農翻身做主人,真是這個月最開心的事情了。接下來就是把所有code改好build pass就好。小G用angular已經兩年多了,一開始用的angular做了一個officeapp,公司看不錯就migrate到angular2 的webapp,所以小G是經歷過angular1和angular2的人,看過angular1的各種丑和angular2的各種帥。所以這篇文章主要是強推angular2的軟文,主要快速上手angular2,介紹一下angular2的主要優勢,快速接觸angular2的一些語法及 Component,Service的用法。還有就是介紹小G最喜歡的rxjs,因為angular2已經基于rxjs了,把所有東西變成stream然后各種神操作。當然一篇blog不足夠介紹這么多,所以小G會分以下幾塊:

  1. 本篇blog會初步介紹angular2的一些簡單語法及快速上手。
  2. 下一篇blog會介紹angular form 的用法
  3. 再下一篇blog會介紹angular2里面的dependency injection的主要用法以及用ood的方法來做dom manipulation。
  4. 下下篇最重要會介紹小G最愛的rxjs。
  5. 小G還會寫個cheatsheet,關于angular2的主要用法以及rxjs的主要用法。rxjs的主要用法按decision tree的方法展示。

參考資料

我是第一次見有公司能把framework的文檔寫的這么好的,google真是給了我驚喜。如果大家不想從頭開始寫,小G我寫了個簡單app,囊括了google angular2文檔里的tutorial。這里上鏈接:
Angular 2 quick start. 所以這個app的文件結構是這樣的:

├──angular2/                                    
│   │
│   ├──app/                               
│   │   ├──boot.ts                          
│   │   ├──app.component.ts   
│   │   ├──hero/                  //這篇博客用   
│   │   |   |──hero.component.ts
│   │   ├──hero-form/             //form blog 用
│   │   |   ├──hero.ts                         
│   │   |   |──hero-form.component.ts
│   │   |   |──hero-form.component.html
│   │   ├──hero-list/             //dependency injection 用
│   │   |   ├──...
│   ├──index.html
│   ├──package.json   //用來安裝我們需要的庫, 以及node的一些命令
│   ├──tsconfig.json  //用來配置typescript
│   ├──style.css      //這個playground的css

package.json

用過前端的都知道,npm拯救了世界。所以我們用angular2的時候肯定也會用上npm來幫我們加各種庫。所以對node或者npm熟悉的肯定也知道package.json。 在package.json里面,你可以定義script:
"scripts": {
    "tsc": "tsc",
    "tsc:w": "tsc -w",
    "lite": "lite-server",
    "start": "concurrent \"npm run tsc:w\" \"npm run lite\" "
 },

在這里你可以設置你一會要用npm跑的命令,以這個為例,如果你跑npm start,那他就會先跑npm run tsc用tsc compile typescript到javascript,然后跑npm run lite跑server來host整個app。
還有dependencies和devdepdencies,你可以在里面加你想要使用的庫,這樣你就可以用npm install安裝你所有想要的庫。這里有個小trick,如果你想把這個庫裝到系統里面,就要跑

1 
npm install -g [test] 

如果你只想隨便使用一下,就跑:

1 
npm install [test] 

如果你不僅想用還想加到packge.json里面,那就要使用

1 
npm install --save [test] 

typescript.json

這個文件主要用來配置typescript的compiler,比如用啥target,用啥module,是不是要設置sourcemap,是不是要要設輸出路徑什么的。小G在這里配置一個輸出dist,這樣生成的js和map就不會和tsfile合在一起,他們會到一個單獨的文件夾,
然后index.html會去查找。

index.html

這個是整個app存在的html支持,angular2說白了還是javascript,它是不能脫離html的存在。所以跟普通的javascript一樣,需要html來load這個框架。在這個例子中小G就使用了systemjs,這個庫能找到angular2 的入口然后把整個app load出來。
當然不僅僅可以使用systemjs,還有一些其他的框架比如webpack,可以bundle你的庫讓你的庫不再成為一團亂麻。不過代價是他會有個很奇怪的build 方式,他有個server來查看你的code的改變然后在memory里面compile typescript然后把編譯好的javascript放到memory里面然后用webpack dev server host然后讓index.html直接找,這樣的壞處是在debug的時候sourcemap很難找。雖然chrome debugger可以很容易解決這個問題。但是其他編譯器比如vscode的chrome debugger extension就沒有那么智能了。小G曾經嘗試用vscode debug angular webpack starter,過程非常痛苦。

boot

Angular2 對于angular1一個最大的進步是所有的東西都模塊化了,web component好像變成了現在web technology的一個趨勢。比如google正在推崇的polymer就完全使用了web component的思想,他給你很多個component,就像搭積木一樣把你要的component下載下來,然后搭起來搭成你想要的一個web app。小G覺得這個想法是很不錯,不過小G試了下polymer反應還是有點慢,雖然那些component做的很好看很material design,但是用戶體驗太慢的話還是不行吧。但是我相信polymer一直在進步,總有一天可以很好的使用它。這個boot等于整個app的入口,在boot.ts里面加入了這個app的root component,然后在index里面用systemjs調用這個boot,就把這個app整個load起來了。具體如下:
index.html
    |
    |systemjs調用boot
  boot
    |boot調用模塊化app的root component
    |
  app

而boot在調用模塊化的component root的時候使用了bootstrap()的函數,我們可以importanglar2/core來得到bootstrap()這個函數。看到這里大家可能要想為啥不直接用index load app 為啥要通過一個boot呢?確實如果只想做web app,可以直接用systemjs來load app。有boot的原因是因為我們可能不僅僅想做web application,
我們還想做native app, 還想做cordova或者ionic的app,這樣只需要替換boot其他所有的代碼都可以復用,這是angular2的一個很大的改善。angular1里面并沒有很好的支持這一個功能。

app

正如小G剛才所說,angular2把所有的組建都模塊化了,在angular2里面,你的整個app 可以變成很多個模塊,這些模塊可以定義輸入輸出,也可以繼承,可以拼接,這些模塊就是不同的component,component之間的通信,數據交換就用service。在小G寫的例子里,可以看到就加入了三個模塊:hero,hero-form,heros-list。
@Component({
    selector: 'my-app',
    template:`
    < hero>< /hero>
    < hero-form>< /hero-form>
    < heroes-list>< /heroes-list>
    `,
    directives:[HeroComponent, HeroFormComponent,HeroesListComponent]
})

首先@Component是angular2里面新引進的函數,通過這個函數我們可以設置selector,template,directives,styles等等。當然如果你要使用Component這個函數就要引入庫:

1 
import {Component} from 'angular2/core'; 
當然還可以引入子模塊,用相對路徑即可:
import {HeroComponent} from './hero/hero.component';
import {HeroFormComponent} from './hero-form/hero-form.component';
import {HeroesListComponent} from './hero-list/heroes-list.component';

selector

主要用來定義外部的模塊如何使用這個模塊。比如在app.component中selector是my-app,那在外部的index.html里面要load app.component這個模塊就要使用

template

主要用來定義這個模塊里面的html結構,他也可以加入內部的模塊,比如這個 app.component就加入了三個不同的子模塊。這樣寫html是不是好像就像搭積木一樣簡單了?有一點要注意的是當template引用html 的時候需要使用‘`’符號,一般這個符號在鍵盤上數字鍵1的左邊。
在template里還有一個很重要的概念,用過angular1的童鞋都知道怎么在html里面引用controller里面的變量,沒錯,用{ { } },在angular2里面也一樣。 我們在class里面定義了一個變量,在template里面就可以用{ { } }直接引用。例如:
@Component({
    selector:'hero',
    template: `
          < div >{{title}}< /div >
       `
})
export class HeroComponent {
    public title = 'Tour of Heroes';
}

這樣可以在template直接引用class里面的title,等于template里面是< div>Tour of Heroes< /div>

然后你就可以隨意改這個變量,然后render出來的html也會跟著改變。
另外我在template里面想提到的是@Input @Output factory method以及[(ngModel)]的雙向綁定。

@Input
這個@Input是用來定義模塊的輸入的,用來讓父模塊往子模塊傳遞內容:
@Component({
  selector: 'bank-account',
  template: `
    Bank Name: {{bankName}}
    Account Id: {{id}}
  `
})
class BankAccount {
  @Input() bankName: string;
  @Input('account-id') id: string;
  // this property is not bound, and won't be automatically updated by Angular
  normalizedBankName: string;
}
@Component({
  selector: 'app',
  template: `
     < bank-account bank-name="RBC" account-id="4747">< bank-account>
  `,
  directives: [BankAccount]
})
class App {}

再這個例子中,父模塊是app,子模塊是BankAccount, 在app中我們想往子模塊里面傳遞back-name和account-id這兩個信息,可以通過property的方式最簡單直接,而子模塊要接受這個 property就要用@Input來接收。子模塊會在BankAccount里面直接接收傳遞過來的property。傳遞的方式可以是駝峰法,也可以直接寫在input里面,就如
例子里面寫的那樣。要記住一點的是父模塊在引用子模塊的時候是用的[]。

@Output
如果我們的子模塊想自定義一些event傳遞給父模塊又該怎么做呢?這時候就要用到@Output了。
@Directive({
  selector: 'interval-dir',
})
class IntervalDir {
  @Output() everySecond = new EventEmitter();
  @Output('everyFiveSeconds') five5Secs = new EventEmitter();
  constructor() {
    setInterval(() => this.everySecond.emit("event"), 1000);
    setInterval(() => this.five5Secs.emit("event"), 5000);
  }
}
@Component({
  selector: 'app',
  template: `
    < interval-dir (every-second)="everySecond()" (every-five-seconds)="everyFiveSeconds()">
    < /interval-dir>
  `,
  directives: [IntervalDir]
})
class App {
  everySecond() { console.log('second'); }
  everyFiveSeconds() { console.log('five seconds'); }
}

因為在普通的html里面,比如button我們會有onclick這種event來監聽這個button是否被按了,然后angular2也完全允許我們自定義這種event listening的模式,我們可以給任何模塊定義這種event,當觸發了event之后就會從子模塊往父模塊傳遞子模塊的信息。

再這個例子里,父模塊是app,子模塊是IntervalDir, 然后在子模塊定義event觸發的條件,比如每隔1s要觸發事件,每隔5s要觸發事件。然后當父模塊監聽到這些事件時可以做相應的操作。當然我們如果想傳遞信息,可以在new EventEmitter()里面加入我們想要傳遞的東西,然后在使用的時候加入函數的參數里面。比如我們想傳遞一個
test,我們只需要這么改:
class IntervalDir {
  @Output() everySecond = new EventEmitter(test);
}
< interval-dir (every-second)="everySecond(test)" (every-five-seconds)="everyFiveSeconds()">
everySecond(test) { console.log(test); }

而在這里,父模塊在引用子模塊的時候是用的()。

[(ngModel)]

最后當然是最經典的angular特有的ngModel雙向binding了。而這個特性是< input >特有的。我們注意到了 [(ngModel)] 既有[]也有()。沒錯它既有Input的特性也有Output的特性。

1 
< input [(ngModel)]="hero.name" placeholder="name" > 

在這里,我們在view里面改input里面的內容,hero.name也會跟著改變,而如果我們在class里面改變hero.name在view里面的內容也會跟著改變。然后就是mvvm的世界了。

directives

主要是加入子模塊的模塊,當我們定義了一個模塊之后,如果我們想要它被別的模塊使用,必須定義一個出口被別的模塊使用,比如app.component這個模塊最后就要:

1 
export class AppComponent {} 

讓angular2知道它是一個AppComponent模塊,然后在boot里面可以加入這個模塊。同理我也export了HeroComponent,HeroFormComponent以及HeroesListComponent模塊。然后在app.component的一開始就import進來,然后就要在directive加入這些模塊然后在template才能識別相應的selector。如果
不在directive中引入相應的模塊,那在compile的時候template就不知道相應的selector是啥就不能正常的render了。

providers

這個主要用來加入service的模塊。當我們想在模塊之中使用service的時候,和directive相同的道理,我們需要加入provider這樣這個模塊就知道使用的service的provider。小G在用angular的過程中碰到最多的問題就是missing provider的問題,在angular1中可能是由于service的dependency之間有loop,
表示service互相依賴,會有問題。但angular2由于模塊化了這個dependency injection的問題得到了很好的解決。如果再碰到這類問題首先要檢查模塊是否加入了service provider。

styles

這個主要定義這個模塊使用的css,不用放到外部的style.css里面。這樣這個模塊的css完全由自己掌控,是不是方便了很多?

這整個app的root component介紹完了,這個root component主要功能是加載了其他模塊。這個博客還會介紹一個hero component。

hero component

這塊主要介紹的就是template里面的input和output還有ngFor:
< li *ngFor="#hero of heroes" 
    [class.selected]="hero === selectedHero"
    (click)="onSelect(hero)">
    < span class="badge">{{hero.id}}< /span> {{hero.name}}
< /li >

比如我們有一個list的heros,我們可以在html里面用ngFor來循環這個list然后把list里面的英雄輸出到html里面。在這里的語法和angular1完全不一樣了。在angular1里面,完全沒有以及#的符號,但是在angular2里面,和#確實很關鍵的語法。
( )這個在ngFor的前綴表示整個< li >元素以及它的子元素合成一個master模板。如果不想使用( ),ngFor需要被包含在一個template的元素里面:
< template ngFor #hero [ngForOf]="heroes" >
  < hero-detail [hero]="hero" >< /hero-detail >
< /template >

Angular2還有這個語法的就是ngIf。如果不用()也需要把ngIf包含在template里面。
而在hero前面的( # )表示了hero是一個本地模板變量,整個合起來就是循環heros的list,然后對于每個hero,在< li >< /li >內可以進行操作。
從上面的例子還可以看到input和output。只不過這兩個都已經在li模塊里面集成好了,不需要自己定義。所以對于li這個元素的input,我們可以定義這個li的class的是否被選擇。對于li元素的output我們可以定義點擊事件監聽。然后在這個模塊中進行相應的函數操作。

小結

洋洋灑灑這么多,其實angular2的主要知識點有下面幾個:

  1. Angular2的文件結構,typescript的設置,package.json的設置。
  2. boot的作用,更換boot可以達到復用代碼讓代碼工作在其他framework的作用。
  3. Angular2是模塊化的,自上而下的一個樹狀結構。每個模塊之間可以互相調用,也可以用service互相通信。
  4. Angular2里面的一些概念,比如Component,Directive,Provider,selector,template, @Input, @Output, [ ( ngModel) ], ngFor, ngIf.

如果你知道上面這些是咋回事,那差不多可以開始自己寫個angular2的app啦。一方面可以在小G的簡單app上隨便操作看效果,另一方面小G也給個angular2的快速開發app的project:angular2-webpack-starter。小G就是用這個來做比較大型的app開發的。這個項目是跟著angular2不斷在更新的,比較傷感的是用vscode很難debug。

本文標題:Angular2 初探

文章作者:G

發布時間:2015年12月21日 - 23時30分

最后更新:2015年12月23日 - 15時39分

原始鏈接:http://gabriel0402.github.io/2015/12/21/overview/

許可協議: "署名-非商用-相同方式共享 3.0" 轉載請保留原文鏈接及作者。

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!