Angular 1.5 Styleguide (ES2015)

說到關於 Angular Styleguide,不少人可能會想到這篇經典的文章。的確,它是一篇很是棒的文章,甚至已經被翻譯成許多種語言(包括中文),在 github 上更是擁有將近 1.9w 個 star。html

然而,此次談論的不是它。由於隨着 ES6 的普遍應用,以及 Angular 1.5 的發佈,它有那麼一點點不夠時髦(也談不上過期哈~)。webpack

本文的大部分觀點都來自這篇文章(如下簡稱原文),但我的根據工做上積累的一些經驗添並非徹底認同原文的全部想法,並想去除些繁冗的例子,因而就沒有直接翻譯原文。git

言歸正傳,下面就來看看使用 ES6 來編寫基於 Angular 1.5 的代碼有哪些最佳實踐。angularjs

模塊架構

在 Angular 體系中,全部代碼都是基於模塊的,它來封裝模塊內部的邏輯、模板、路由和子模塊。github

模塊劃分

原文將模塊分爲 3 大類,分別是:root, component 和 common,並建立相應的文件夾來儲存。web

  • root:根模塊組件,用來啓動應用和相應模板typescript

  • component:包含全部可重用的模塊,模塊中能夠包含 components, controllers, services, directives, filters and testsredux

  • common:包含全部業務的模塊(即不可重用,和 component 最大的區別),它能夠是頁面佈局、導航和頁腳等等。api

原文中有詳細的例子,但就如文章開頭所說,在這裏就不貼了。babel

可是,我並不徹底認同原文觀點。

由於,common 的翻譯是公共的,在 common 中存放業務代碼也和咱們一直以來的作法相悖;其次是,在 Angular 的開發過程當中,仍是存在一些能夠在業務邏輯中公用的代碼,好比 service 和 filter。因此,我更傾向於將它分爲 4 部分,分別是 root, app, component 和 common。

  • root:和原文的做法同樣,依舊是用來啓動應用,幷包含了應用的模板(並不必定要一個文件夾,能夠是根目錄下的一個 app.js 文件)

  • app:相似於以前的 common 模塊,包含全部的業務模塊組件

  • component:同原文的同樣,包含全部可重用的模塊組件

  • common:公用代碼模塊,包含可公用的代碼,如 service 和 filter

附一張項目中的代碼結構圖

模塊導出

使用 ES6 確定會使用強大的模塊語法,在同 Angular 一同使用時,必定要注意導出的是模塊的名字,而非是 Angular 的模塊對象,這樣才能再另外一處被其餘模塊注入。

// 精簡了原文的代碼,去除了一些和這節無關的代碼
import angular from 'angular';
import CalendarComponent from './calendar.component';

const calendar = angular
  .module('calendar', [])
  .component('calendar', CalendarComponent)
  .name;

export default calendar;

文件命名

首先,爲每一個模塊添加 index.js 文件來定義整個模塊,這樣再別的模塊中能夠經過文件夾直接引入。

原文使用模塊名.文件內容.文件類型的方式來命名一個文件,如 calendar.controller.js 等。

我徹底贊成第一個觀點,但第二個中的模塊名就沒有添加的必要,由於文件夾名已經很好的體現了模塊名這個含義。

再附一張項目中的模塊結構圖

組件(Component)

組件是 Angular 1.5 新提出的,是一種特殊的指令,Augular 的源碼中也彰顯了這一點。

它相比指令更多的是數據的單向綁定和生命週期鉤子,儘管我認爲所謂的生命週期鉤子只是語法糖,甚至組件它自己就是個語法糖,但這不妨礙它成爲 Angular 體系中重要的一部分。由於,它的推出明確的區分了指令和組件,解決了原先指令劃分不清、承擔過多工做的問題。

組件屬性

Property Support
bindings Yes, 只使用 @, <, &,避免使用 =
controller Yes
controllerAs Yes, 默認爲 $ctrl
require Yes
template Yes
templateUrl Yes
transclude Yes

控制器(controller)

控制器只應在組件中使用,若是你只想建立一個控制器,那你應建立一個無狀態組件來管理它。

使用 class 關鍵字來建立控制器時要注意如下幾點:

  • 使用 constructor 處理依賴注入

  • 以前提到過,導出模型名,而並非直接導出模型

  • 使用箭頭函數

  • 使用 $onInit, $onChanges, $postLink$onDestroy 生命週期
    (注意:$onChanges 會在 $onInit以前被調用)

  • 使用默認的控制器 $ctrl,不使用 controllerAs 修改控制器的別名

單向數據流

  • 老是使用 < 單向數據綁定來代替 = 雙向數據綁定

  • 使用 $onChanges 來監聽數據的變化

  • 父組件的方法使用 $event 做爲參數傳遞的名字

  • 子組件調用時返回一個包含有 $event 屬性的對象

這是否是看上去很像 Redux?沒錯,原文的做者也是推薦使用 Angular Redux 來管理狀態。

狀態組件(Stateful components)和無狀態組件(Stateless components)

狀態組件和無狀態組件其實分別對應了 Redux 中的容器組件(Smart/Container Components)和展現組件(Dumb/Presentational Components),這部分原做者主要也是表達了在 Angular 中實現單向數據流的理念,但原做者提供的例子並非完整的 Redux,它沒有單一的 Store 和 Reducer。

指令(Directive)

相信指令你們都很熟悉了,但自從 Angular 1.5 提供了組件,指令的選擇就應當慎重考慮,它應當只在裝飾 DOM 時使用。

  • 不使用 template, templateUrl, scope, bindToControllercontroller 等相關的屬性,若是想用,考慮是否是它能夠用 component 來實現

  • 老是使用 restrict: 'A'

指令屬性

Property 是否使用 Why
bindToController No 使用組件替代
compile Yes DOM 操做/事件的預處理
controller No 使用組件替代
controllerAs No 使用組件替代
link functions Yes DOM 操做/事件的處理
multiElement Yes See docs
priority Yes See docs
require No 使用組件替代
restrict Yes 老是使用 restrict: 'A'
scope No 使用組件替代
template No 使用組件替代
templateNamespace Yes (若是必須) See docs
templateUrl No 使用組件替代
transclude No 使用組件替代

服務(Service)

服務主要用於封裝一些不該在組件中處理的業務邏輯和請求。

Angular 提供 2 種建立服務的方式 servicefactory。在 ES6 引入了 class 關鍵字後,它能很是友好地同 service一塊兒工做,因此,不管什麼時候都使用 service 來建立服務。

類 or 方法

原文的標題是常量或類(Constants or Classes),允許我自做主張的修改一下標題,由於我認爲原文的實現的區別更主要的在因而使用類或方法去定義一個服務或控制器等。

固然這兩種方法均可以,由於類它自己就是方法的一個語法糖。可是,Angular 2 是重度依賴 class 關鍵字的,因此,我認爲仍是所有統一使用 class 關鍵字來聲明服務、控制器、過濾器、指令和組件的定義等。

值得注意的是,Angular 組件和指令定義的參數是一個對象,因此在使用 class 定義時,要手動實例化它。

工具

最後,原文做者還推薦了一些工具

  • Babel:編譯工具,這就很少說了,必備神器

  • TypeScript:仍是爲了 A2

  • Webpack:打包工具,用過都說好

  • ngAnnotate:自動依賴注入,和打包工具一塊兒服用效果更好

  • Angular Redux:狀態管理

以上爲我的觀點,歡迎交流。

相關文章
相關標籤/搜索