angular1.0的這些繁雜的api,還有它的執行速度,運行效率,學習曲線,都被人吐槽,最近一直在用ng1,實在很想吐槽。
最近寫ng2的項目,寫了一些ng2基礎的應用(包括angular-cli,路由,表單驗證,組件通信,ajax,服務/指令,lazyload)demo,地址在->點我
學了一下angular2,看它有什么區別呢?
我就不復述網上一堆的對比言論了,我僅僅對我項目里用到的一個點來進行闡述。
有個需求就是一個radio對應一個input標簽,比如有兩對。
我需要選中1的時候傳輸1的value,選中2的時候傳2的vaule。當選中1,2的input必須置空,選中2的時候1可以有值。還需要拿到數據以后還能顯示回這個頁面。
ng1做的時候要radio倆ngModel,input倆ngModel,你需要判斷radio是不是被選中。input的ngModel就不用管了。(好的辦法是用事件代理,這樣在傳輸數據沒問題,很簡單,數據回顯的時候就要根據數據推radio的選中情況了,不操作dom的情況下還需要加ngModel,不過也是沒辦法的事,不然改交互好了)
重要的一點是你必須$watch radio對應ngModel,如果沒被選中,那2框置空。。坑的是如果我有好幾個表單,我需要循環表單$watch!!!!坑死了。性能超差。(因為可能在代碼里修改radio對應的ngModel來手動完成radio的唯一性,不然也不需要watch,事件代理也一樣坑,回顯的時候也必須手動維護一個數組來模擬radio的原生特性,但是可以避免$watch,因為發送請求數據不需要radio的狀態,所以正在強烈建議重構這個頁面)
開始ng2-----------------------------------------------------------------
ng2一個好的點就是ngModel的轉變,它做的很棒的一點是單項綁定和雙向綁定的選擇,ngModel也是。()是數據到模板的綁定,[ngModel]是模板到數據的綁定。
ng2有Attribute, Class, and Style 綁定,Event Binding。而且都是可以拼接字符串或者在binding里面寫表達式,甚至是函數,比如:
ckass(){
return " abc dec"
}
<input type="text" #spy1 [ngClass]="'hahaha'+ckass()" />
想用的心已經蠢蠢欲動了。。
普通的雙向綁定如ng1是這樣寫
<input type="text" [(ngModel)]="input" />
重要的是它可以拆開:
<input type="checkbox" [ngModel]="input" (ngModelChange)="handleChange()"/> {{ input }}
(ngModelChange)是啥,它里面可以隨便寫嗎?
答案是不能。借用雪狼大叔的翻譯:安利一下angular.live
ngModelChange
並不是<input>
元素的事件。 它實際上是一個來自ngModel
指令的事件屬性。 當Angular在表單中看到一個[(x)]的綁定目標時, 它會期待這個x
指令有一個名為x
的輸入屬性,和一個名為xChange
的輸出屬性。
雙向綁定的指令都會有一個xxChange的屬性,它可以修改綁定。比如我們給它加個條件,如果radio選中了,就可以綁定啦, 不然你就是空吧。
<button class="batton" (click)="handleClick($event)"> click me</button> <input type="checkbox" [ngModel]="input" (ngModelChange)="handleChange()"/> <input type="text" [(ngModel)]="input" [disabled]="!check" /> {{ input }}
export class AppComponent { check = false; handleChange(){ this.check = !this.check; if(!this.check) { this.input = ""; } } handleClick(e: any) { this.check = false; } }
這里留一個button來解決程序修改radio狀態的問題。可以看到,我們的handleChange其實就做了一個手動綁定的工作。如果沒選中給置空。
運行你會發現,點擊click me,input的內容並木有置空,因為radio的修改不是模板到數據的過程,是數據到模板的過程。
沒關系,[ngModel]的單項綁定仍然可以自己控制,比如:
@Component({ selector: 'my-app', template: ` <button class="batton" (click)="handleClick($event)"> click me</button> <input type="checkbox" [ngModel]="handleCheck()" (ngModelChange)="handleChange()"/> <input type="text" [(ngModel)]="input" [disabled]="!check" /> {{ input }} `, styles: [``] })
又來了個handleCheck,這是ng1的ngModel不能搞定的。反正不支持處理函數。
那ng2咋寫:
export class AppComponent { check = false; handleCheck(){ if (!this.check) { this.input = ""; } } handleChange(){ this.check = !this.check; if(!this.check) { this.input = ""; } } handleClick(e: any) { this.check = false; } }
我們在數據到模板的綁定只需要判斷是否選中就可以了,這樣就避免了$watch。
還有一些表達方式的不一樣,主要是因為都換成ts了,一些類似es6的語法都開始發揮作用。
1.模塊注入
因為es6的語法,去掉了ng1的依賴注入,改為模塊化的注入,import語法
import { Component } from '@angular/core';
export class AppModule { }
2.模塊化
由於ng2的模塊化,原本模塊化不那么明顯的ng1的語法要改變很多,模塊都作類,新增了注解語法,
@Component({ selector: 'hero', templateUrl: 'component.html' }) export class HeroFormComponent { ... }
Component注解規定了這個模塊的selector,和模板template,然后把這個類做控制器。
3.數據展示
基本類似ng1,雙花括號的展示方式
import { Component } from '@angular/core'; @Component({ selector: 'my-app', template: ` <h1>{{title}}</h1> <h2>My favorite hero is: {{myHero}}</h2> ` }) export class AppComponent { title = 'Tour of Heroes'; myHero = 'Windstorm'; }
只是模板選擇器寫在了注解里,控制器為此類。
然后這個類就可以做為一個模塊使用,其實就是ng1的組件型指令
<my-app>loading...</my-app>
另外,template里的一些自帶指令也是類似ng1,只是寫法不同,除了上面寫的綁定意外,再說一個ngFor
template: ` <h1>{{title}}</h1> <h2>My favorite hero is: {{myHero}}</h2> <p>Heroes:</p> <ul> <li *ngFor="let hero of heroes"> {{ hero }} </li> </ul> `
就是類似ng-repeat的作用了。只是換了個語法,看文檔就好了。
4.dom事件
為了使鍵盤事件比較方便,然后自己封裝進了ng2,vue已做此工作
<input #box (keyup.enter)="update(box.value)" (blur)="update(box.value)">
其余的事件都是類似的,帶有()括號的單向綁定。
5.服務
服務也有點差距,注入和聲明有點不同,此為聲明
import { Injectable } from '@angular/core';
@Injectable()
export class HeroService {
...
}
當 TypeScript 看到@Injectable()
裝飾器時,就會記下本服務的元數據。 如果 Angular 需要往這個服務中注入其它依賴,就會使用這些元數據。
使用服務首先引入服務
import { HeroService } from './hero.service';
然后需要在注解里注冊一下
providers: [HeroService]
然后在這個類中就可以使用這個服務了
export class AppComponent implements OnInit { title = 'Tour of Heroes'; heroes: Hero[]; constructor(private heroService: HeroService) { } getHeroes(): void { this.heroService.getHeroes().then(heroes => this.heroes = heroes); } ngOnInit(): void { this.getHeroes(); } }
6,生命周期
ng2增加了很多生命周期,如上面的ngOnInit等等,都是ng1沒有的,就不介紹了
7,http
跟ng1類似ng2也是封裝了ajax到http,不同的是現在的ng2可以用rxjs了。。rxjs好像貴族的東西,用的人很少,學習成本不低,但是好用。ng2的http不是封裝的promise了,而是簡化的rx的Observable,需要subscribe來執行他的請求。也可以引入rx的toPromise,然后then下去就可以了。有點強破推銷的意思。
8.管道
其實就是ng1的filter。
import { Pipe, PipeTransform } from '@angular/core'; /* * Raise the value exponentially * Takes an exponent argument that defaults to 1. * Usage: * value | exponentialStrength:exponent * Example: * {{ 2 | exponentialStrength:10}} * formats to: 1024 */ @Pipe({name: 'exponentialStrength'}) export class ExponentialStrengthPipe implements PipeTransform { transform(value: number, exponent: string): number { let exp = parseFloat(exponent); return Math.pow(value, isNaN(exp) ? 1 : exp); } }
@Pipe
裝飾器告訴Angular:這是一個管道,管道類實現了PipeTransform
接口的transform
方法,該方法接受一個輸入值和一些可選參數,並返回轉換后的值。transform
方法返回就處理后的值。
9.路由
路由配置沒什么說的,跟着文檔一步步來就好了,由於是import的引入,不存在ng1包含路由很大的情況,根據配置來就好了。這種框架的路由都是類似的。
10. 組件交互
ng1現在都忘記了,主要說一下ng2的組件交互。
父傳子的交互方式是靠props來傳遞的,這點跟react一樣了,子組件的狀態是純靠輸入,這是material的分頁組件,在子組件里需要用裝飾器來取,@input。下面例子就有
<md-paginator #paginator [length]="xxx" [pageIndex]="0" [pageSize]="10" [pageSizeOptions]="[10]"> </md-paginator>
子傳父組件是不建議的,但也有很多需求,比如打開一個子組件做modal,然后modal關閉的時候回傳給父組件數據,對於react的方案一個是redux,另一個包括ng1也在用的就是事件系統。都有各自的事件系統,
但是ng2的事件系統最為強大,因為它是rxjs。
這里給一個例子:subject就是rxjs的對象。關於rxjs的介紹另有博文:rxjs-流式編程
@Component({ selector: 'wap', template: '<app-add-warp [subject]="subject" ></app-add-warp>' }) export class addWarpComponent { subject = new Subject(); constructor() { this.subject.subscribe({ next: (v) => console.log(v) }); }; }
@Component({ selector: 'app-add', templateUrl: './add.component.html', styleUrls: ['./add.component.scss'] }) export class AddComponent implements OnInit { @Input('subject') cbSubject:Subject<any>; constructor() { } ngOnInit() { this.cbSubject.next(this.user); } } }
subscribe就是觸發事件要執行的東西,next方法就是觸發事件的點。