Angular 5 是啥玩意?


Angular 5即將在近期發布,讓我們來看看有啥特別的呢?

沒用過 Angular 也聽過 Angular,沒聽過 Angular 總之你現在看過了 XD
Angular 5即將發布,本文將介紹什麼是 Angular 以及新版本有啥有趣的東西。本文為了友善初學者,會從最基礎的東西講起,如果想直接看版本 5 的新功能可以直接跳到後面。

簡介

首先簡單描述一下什麼是 Angular,改編自官網:

Angular是一個前端開發平台。它能幫你更輕鬆的構建 Web應用程式。 Angular 集聲明式模板(declarative templates)、依賴注入(dependency injection)、端到端工具和一些最佳實踐方式於一身,為您解決開發層面的各種挑戰。 替開發者提升構建 Web、手機或桌面應用程式的能力。

Angular是一個前端開發平台。它能幫你更輕鬆的構建 Web應用程式。 Angular 集聲明式模板(declarative templates)、依賴注入(dependency injection)、端到端工具和一些最佳實踐方式於一身,為您解決開發層面的各種挑戰。 替開發者提升構建 Web、手機或桌面應用程式的能力。

Angular 是 Google開發出來一款開源 JavaScript框架,用來開發單一頁面應用程式(single page application, SPA)。Angular 共有 1、2、4、5 這麼多版本,1正名為 AngularJS ,而 2、4、5 版為 Angular。兩者架構差異很大,簡單來說 AngularJS 本身有些缺點,後來受到 React 的刺激後,Angular 便被開發出來與之抗衡。

Angular 採用 MVC 模式,涵蓋了M、V、C/VM 等層面,不需要組合、評估其它技術就能完成大部分前端開發任務。這是因為她已經將各種技術封裝在框架中,隔離了瀏覽器的細節,讓你不用關心她的實現細節。此外所有需要使用的套件、模組 Angular 都已經幫你打包好了,不像是 React 或 Vue 要自己去架構模組。

特色

採用 Typescript

簡單來說 Typescript 可以說是 Super版的 JavaScript,採用強型別並增加對物件導向的支援。更詳細可以參考這篇

注入依賴

Angular 中的 Service 物件帶有依賴注入的概念。依賴注入的觀念就是將所有東西先在「外面」準備好,然後再帶入「內部」的程式中,同時只會生成單一實體。如此一來你就能夠在檢視程式碼的時候,一目了然地知道「內部被注入」的這個物件「依賴著外部」的哪些物件。更詳細可以參考這篇

模組、組件與模板

Angular 中將一個網站應用程式拆程一個一個的組件(Component),而每個組件又可以是更小的組件所構成,而這種方式在現代前端開發框架中已經非常常見,在 React 與 Vue 中也可以看到差不多的概念。好處是一個功能為一個組件,彼此獨立,在修改、抽換上都比較方便,日後維護和拓展也方便。

更詳細一點的話 Angular 中除了Component 還有 Service、Directive、Pipe Router等等物件,概念都和組件很像,但受限於篇幅,這邊不介紹,大家可以去 Angular Doc 上面看或參考這篇

而每個組件由三塊所構成,分別為 component.htmlcomponent.csscomponent.ts,由 ts 來做邏輯處理,並串連 HTML 模板和 CSS。模板藉由和 ts 數據綁定以及套上 DirectivePipe 使的網頁呈現和邏輯更加強大。關於模板可以參考這篇

而所有組件整合在一起可以變成一個模組(module),一個 Angular 開發的應用程式可以同時使用好幾個模組。總之,整個架構就像曡積木一樣,積木又可以是更小的積木,最後蓋出成品。

開發層面

  • Angular 自帶整合開發環境 Angular CLI 開發更加方便,webpack 什麼都都幫你弄好了。

關於 Angular 更多詳細細節可以參考 Angular 2 給初學者的學習指南 雖然是針對 2 寫的,但內容都是最基礎的,而最基本的概念 2、4、5 都一樣,概念懂了之後再去研究不同版本的更細節差異。


Angular 5 強勢來襲

說了這麼多,所以 5 到底有哪些新功能呢?

更好的行動裝置體驗

@angular/service-worker 套件讓 Angular 更好的實踐 Progressive Web Apps

Angular CLI

AOT 編譯現在是預設的編譯方式,意味著 AOT 有更好的提昇。但編譯時間還是比較長。建議是在開發時用 JIT,發布時再使用 AOT。

效能更好 & 體積更小

初始化和編譯速度都有提昇,更好的優化讓 bundle的大小也變小了,event listener 的速度提高三倍。

Multiple exportAs

Directive 可以定義多個名字作為變數在模板中使用

@Directive({
selector: 'child-dir',
exportAs: 'child1, child2'
})
class ChildDir {}

@Component({
selector: 'main',
template: `
<child-dir #c1="child1" #c2="child2">
<!-- c1=== c2-->
</child-dir>`
})
class MainComponent {}

Bootstrap with Custom Zone

自由選擇要用的 Zone

platformBrowserDynamic()
.bootstrapModule(AppModule, {
ngZone: 'zone.js' // or 'noop' or Custom NgZone
})

這邊可以看實際效果

Animations

  • :increment / :decrement
@Component({
animations: [
trigger("counter", [
transition(':increment', [ /*...*/ ]),
transition(':decrement', [ /*...*/ ]),
])
],
template: `
<span [@counter]="count">
`
})
class AppComponent() {
count = 1;
}
  • Disable animations
@Component({
animations: [
trigger("anim", [ /* ... */])
],
template: `
<div [@anim]="prop" [@anim.disabled]="animationDisabled">
`
})
class AppComponent() {
prop = '';
animationDisabled = false;
}
  • Negative Query Limit
trigger("anim", [
transition(":enter", [
query(
".item",
[ /** ... **/ ],
{ limit: -5 }
)
])
])

Router

  • ChildActivationStart / ChildActivationEnd
router.events
.filter(e => e instanceof RouteEvent)
.subscribe(e => {
if (e instanceof ChildActivationStart) {
spinner.start();
} else if (e instanceof ChildActivationEnd) {
spinner.end()
}
});
// Event = RouteEvent | RouterEvent
  • ActivationStart / ActivationEnd
router.events
.filter(e => e instanceof RouteEvent)
.subscribe(e => {
if (e instanceof ActivationStart) {
spinner.start();
} else if (e instanceof ActivationEnd) {
spinner.end()
}
});
// Event = RouteEvent | RouterEvent

Forms

  • updateOn
    change, blur, submit
<form [ngFormOptions]="{updateOn: 'change'}">
<input name="foo"
[(ngModel)]="foo"
[ngModelOptions]="{updateOn: 'blur'}">
<input name="bar"
[(ngModel)]="bar"
[ngModelOptions]="{updateOn: 'submit'}">
</form>

http

  • HttpClient 可以直接設定 headers & params
httpClient.get("/api", {
headers: {
"X-MY-HEADER": "header"
},
params: {
"foo": "bar"
},
})

Platform Server

@NgModule({
bootstrap: [MyServerApp],
declarations: [MyServerApp],
imports: [
BrowserModule.withServerTransition({appId: 'render-hook'}),
ServerModule
],
providers: [
{
provide: BEFORE_APP_SERIALIZED,
useFactory: getTitleRenderHook,
multi: true, deps: [DOCUMENT]},
]
})
class RenderHookModule {}

重大改變

  • 需要 TypeScript 2.4.x
import { registerLocaleData } from '@angular/common';
import localeZh from '@angular/common/locales/zh';
registerLocaleData(localeZh);
  • 淘汰 ngFor 改用 ngForOf ,但都還是用 *ngFor 語法糖