背景
由于最近工作的需要罢荡,后端同學(xué)需要開發(fā)后臺(tái)系統(tǒng)的web界面,所以調(diào)研了一些主流的組件化前端框架对扶,比如reactjs区赵,vuejs,angularjs等浪南。其中angularjs屬于具有完整體系的一個(gè)web框架笼才,也就是說不需要額外的前端庫支持,就可以完成一個(gè)前端應(yīng)用络凿。對(duì)于不是很了解前端技術(shù)棧的后端同學(xué)來說比較適合骡送,同時(shí)與AngularJS整合的Typescript,它的語法也和Java比較接近絮记,而且是強(qiáng)類型的語言摔踱。
Angular框架核心模型
當(dāng)然這篇文章并不是用來談?wù)撉岸丝蚣艿募夹g(shù)選型的,而是想從Angular框架的角度來講講前端開發(fā)領(lǐng)域的模型是什么怨愤?
從這個(gè)架構(gòu)圖上我們可以看到里面有很多概念:
- 模塊(Module)
- 組件(Components)
- 模版(Templates)
- 元數(shù)據(jù)(Metadata)
- 數(shù)據(jù)綁定(Data binding)
- 指令(Directives)
- 服務(wù)(Services)
- 依賴注入(Dependency injection)
這里很多概念可能后端開發(fā)同學(xué)反而更加熟悉派敷,比如服務(wù)和依賴注入。當(dāng)然我們今天主要是關(guān)注核心模型撰洗,所以我用模型圖把概念里面的模型單拎出來:
這里我們忽略了元數(shù)據(jù)和依賴注入這兩個(gè)概念膀息,這兩個(gè)我們可以理解成雙向綁定的聲明方式(元數(shù)據(jù)),服務(wù)的調(diào)用方式(依賴注入)所以不放入核心模型中探討了赵。
模塊(Modules)
所謂模塊其實(shí)是語言級(jí)的概念潜支,因?yàn)閖avascript并沒有語言級(jí)的模塊支持,然而幾乎所有的js框架中都有這個(gè)概念柿汛,甚至有很多專門用于實(shí)現(xiàn)js模塊化的框架冗酿。
所以一個(gè)模塊不光可以包含組件(Components)(實(shí)現(xiàn)層面就是一個(gè)用@NgModule聲明的class)埠对,服務(wù)(Services)(實(shí)現(xiàn)層面是一個(gè)普通的class),還可以包含值變量裁替、函數(shù)项玛、類等等。
當(dāng)然Angular的模塊是要依賴語言的包機(jī)制實(shí)現(xiàn)的弱判,一個(gè)典型的Angular模塊:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
@NgModule({
imports: [ BrowserModule ], // 依賴的外部類
providers: [ Logger ], // 提供出去的服務(wù)
declarations: [ AppComponent ], // 屬于這個(gè)模塊的視圖類襟沮,比如components、directives昌腰、pipes
exports: [ AppComponent ], // 提供外部訪問的類
bootstrap: [ AppComponent ] // 聲明模塊的根組件
})
export class AppModule { }
AngularJS里面沒有applicaiton的概念开伏,所以就用一個(gè)根模塊來表達(dá),如下:
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';
platformBrowserDynamic().bootstrapModule(AppModule);
AngularJS里面也沒有顯示libraries的概念遭商,所以也是用模塊來表達(dá)的固灵。
組件(Components)
一個(gè)組件主要是控制著屏幕上的一部分視圖,比如整個(gè)應(yīng)用的導(dǎo)航鏈接劫流。
export class HeroListComponent implements OnInit {
heroes: Hero[];
selectedHero: Hero;
constructor(private service: HeroService) { }
ngOnInit() {
this.heroes = this.service.getHeroes();
}
selectHero(hero: Hero) { this.selectedHero = hero; }
}
在編寫組件的時(shí)候我們需要關(guān)注組件生命周期的擴(kuò)展鉤子:
模版(Templates)
一個(gè)組件的視圖就是一個(gè)模版巫玻,它包含一個(gè)html的框架用來告訴Angular如何渲染組件。
<h2>Hero List</h2>
<p><i>Pick a hero from the list</i></p>
<ul>
<li *ngFor="let hero of heroes" (click)="selectHero(hero)">
{{hero.name}}
</li>
</ul>
<hero-detail *ngIf="selectedHero" [hero]="selectedHero"></hero-detail>
模版可以包含指令祠汇,還可以引用子組件:
指令(Directives)
指令是用來告訴Angular框架如何渲染(轉(zhuǎn)化成DOM結(jié)構(gòu))仍秤。一個(gè)指令就是帶有@Directive聲明的一個(gè)類。一個(gè)組件本質(zhì)上也就是一個(gè)關(guān)聯(lián)模版的指令可很。
除了組件型的指令以外诗力,還有結(jié)構(gòu)型的指令,比如下面的模版就包含兩個(gè)框架自帶的結(jié)構(gòu)型的指令:
<li *ngFor="let hero of heroes"></li>
<hero-detail *ngIf="selectedHero"></hero-detail>
其次還有一種屬性型的指令根穷,用于擴(kuò)展html標(biāo)簽的屬性功能,比如提供值綁定能力导坟。
<input [(ngModel)]="hero.name">
當(dāng)然可能還有其他類型的指令屿良,比如處理布局等等,當(dāng)然你也可以自定義新的指令惫周。
服務(wù)(Services)
服務(wù)很大程度上就是一個(gè)普通的類尘惧,但是我們一般會(huì)給它分配一個(gè)明確的職責(zé),讓它提供某一種特定的能力递递。比如:
- 日志服務(wù)
- 數(shù)據(jù)服務(wù)
- 消息總線
- 稅務(wù)計(jì)算器
- 應(yīng)用程序配置
日志服務(wù)樣例:
export class Logger {
log(msg: any) { console.log(msg); }
error(msg: any) { console.error(msg); }
warn(msg: any) { console.warn(msg); }
}
Angular沒有明確服務(wù)的約束喷橙,但是提供了對(duì)服務(wù)的依賴注入功能:
constructor(private service: HeroService) { }
@Component({
moduleId: module.id,
selector: 'hero-list',
templateUrl: './hero-list.component.html',
providers: [ HeroService ]
})
框架就會(huì)做自動(dòng)匹配,效果如下圖:
總結(jié)
我們今天主要從領(lǐng)域模型的角度去了解AngularJS的總體架構(gòu)登舞,核心模型主要有模塊贰逾、組件、模版菠秒、指令疙剑、服務(wù),從中我們可以感覺到從核心模型的角度去理解一個(gè)復(fù)雜系統(tǒng)的設(shè)計(jì)是很有幫助的,往往能很快的抓到系統(tǒng)設(shè)計(jì)的重心言缤。