前言:AngularJS 是一款來自 Google 的前端 JS 框架,該框架已經被應用到了 Google 的多款產品中,這款框架最核心特性有:MVC、模組化、自動化雙向資料繫結、語義化標籤、依賴注入等待。而且,AngularJS 框架自身是通過 TDD(測試驅動)的方式開發的,從這個角度來看,AngularJS 是敏捷開發的一次成功實踐。
引一段《AngularJS 深度剖析和最佳實踐》中的話:
Angular的學習曲線大概是這樣的:入門非常容易,中級的時候會發現需要深入理解很多概念,高階的時候需要掌握Angular的工作原理,而想成為專家則很難,需要經過很多工程實踐的磨練。
既然入門比較容易,那就一起入門吧。
1、呼叫 Angular
為了使用 Angular,所有應用都必須首先做兩件事情:
- 載入 angular.js 庫
- 使用 ng-app 指令告訴 Angular 應該管理 DOM 中的哪一部分。
如果你正在構建一款純 Angular 應用,則把 ng-app 指令寫在 <html> 標籤中,示例如下:
1 <html ng-app> 2 ... 3 </html>
或者你也可以用 Angular 管理頁面中的一部分,只有放在頁面中的 <div> 之類的元素即可。
1 <html> 2 ... 3 <div ng-app> 4 ... 5 </div> 6 ... 7 </html>
2、模板與資料繫結
1)資料繫結是 Angular 的特色,即 “所見即所得”,像這樣設定其中的文字:
<p>{{someText}}</p>
也叫做雙花括號插值語法,因為它可以把新的內容插入到現有的模板中。
控制器(使用指令 ng-controller)就是你所編寫的類或者型別,它的作用是告訴 Angular 該模型是由哪些物件或者基本資料構成的,只要把這些物件或者基本資料設定到 $scope 物件上即可,$scope 物件會被傳遞給控制器:
1 function TextController($scope) { 2 $scope.someText = someText; 3 }
一個簡單的完整的例子:
1 <html ng-app> 2 <body ng-controller="TextController"> 3 <p>{{someText}}</p> 4 <script src="../src/angular.js"></script> 5 <script> 6 function TextController($scope) { 7 $scope.someText = 'You have started your journey.'; 8 } 9 </script> 10 </body> 11 </html>
載入到瀏覽器中,你會看到:
You have started your journey.
但是大多數應用,還是需要建立模型物件來容納資料,而且並不建議在全域性作用域建立 TextController,建議是定義成模組的一部分。
1 <html ng-app="myApp"> 2 <body ng-controller="TextController"> 3 <p>{{someText}}</p> 4 <script src="../src/angular.js"></script> 5 <script> 6 var myAppModule = angular.module('myApp', []); 7 8 myAppModule.controller('TextController', function ($scope) { 9 var someText = {}; 10 someText.message = 'You have started your journey.'; 11 $scope.someText = someText; 12 }); 13 </script> 14 </body> 15 </html>
記住:把東西從全域性名稱空間中隔離開是一件非常好的事情,模組機制起這個作用。
2)使用 ng-bind 指令,可以在 UI 中的任何地方顯示並重新整理文字,有兩種等價形式:
一種是花括號形式:
<p>{{greeting}}</p>
一種是使用基於屬性的指令:
<p ng-bind="greeting"></p>
花括號插值語法的目的是為了閱讀自然,而且需要輸入的內容更少,但是在頁面載入過程中,Angular 會使用資料替換這些花括號,未被渲染好的模板可能會被使用者看到。
造成這種現象的原因是,瀏覽器需要首先載入 HTML 頁面,渲染它,然後 Angular 才有機會把它解釋成你期望看到的內容。
其實,載入 HTML 頁面一般只發生在首頁,所以對於 index.html 頁面中的資料繫結操作,建議使用 ng-bind,其他頁面可以使用花括號,而且花括號更快一點。
利用 Chrome 瀏覽器的一個針對於 Angular 的擴充套件(AngularJS Batarang(Stable))可以直觀的看到兩者消耗時間的差別:
3)表單輸入
在 Angular 中使用表單元素非常方便,使用指令 ng-model 屬性把元素繫結到你的模型屬性上。
1 <form ng-controller="SomeController"> 2 <input type="checkbox" ng-model="youCheckedIt"> 3 </form>
對於輸入元素來說,你可以使用 ng-change 屬性來指定一個控制器方法,一旦使用者修改了輸入值,這個方法就會被呼叫。下面做一個簡單的計算,幫助消費者計算一下需要付多少錢:
1 <form ng-controller="StartUpController"> 2 Starting : <input ng-change="computeNeeded()" ng-model="funding.startingEstimate"> 3 Recommendation: {{funding.needed}} 4 </form>
把輸入文字框的值設定為使用者估價的 10 倍即可,同時,預設值為 0:
1 function StartUpController($scope) { 2 $scope.funding = { startingEstimate : 0}; 3 4 $scope.computeNeeded = function () { 5 $scope.funding.needed = $scope.funding.startingEstimate * 10; 6 } 7 }
但是為了能夠正確地重新整理輸入框,而不管它是通過何種途徑進行重新整理的,需要使用 $scope 中的 $watch() 函式:
1 function StartUpController($scope) { 2 $scope.funding = { startingEstimate : 0}; 3 4 var computeNeeded = function () { 5 $scope.funding.needed = $scope.funding.startingEstimate * 10; 6 }; 7 8 $scope.$watch('funding.startingEstimate', computeNeeded); 9 }
請注意,需要監視的表示式位於引號中,這個字串會被當作 Angular 表示式來操作。這時我們可以使用一個簡單的模板:
1 <form ng-controller="StartUpController"> 2 Starting : <input ng-model="funding.startingEstimate"> 3 Recommendation: {{funding.needed}} 4 </form>
4)淺談非入侵式 JavaScript
對於大多數內聯的時間監聽器來說,Angular 有一種等價的形式 ng-eventhandler = "expression",這裡的 eventhandler 可以被替換成 click、mousedown、change等。最重要的是,Angular將會幫你遮蔽瀏覽器之間的差異性。
而且不會在全域性名稱空間中進行操作,你所指定的表示式只能訪問元素控制器作用域範圍內的函式和資料。
第二點舉個例子就是,不同的 Controller,可以定義相同名字的資料模型,你會建立一個導航欄和一個內容區域,當你在導航欄中選擇不同的選單項時,內容區域會發生相應的改變。
1 <div class="navbar" ng-controller="NavController"> 2 ... 3 <li class="menu-item" ng-click="doSomething()">Something</li> 4 ... 5 </div> 6 7 <div class="contentArea" ng-controller="ContentAreaController"> 8 ... 9 <div ng-click="doSomething()">...</div> 10 ... 11 </div>
當使用者點選的時候,導航欄中的兩個 <li> 和內容區域中的 <div> 都會呼叫 doSomething() 的函式,你可以在控制器程式碼中寫好這些呼叫所引起的函式,實際上這兩個函式可以是同一個,也可以不是同一個。
1 function NavController($scope) { 2 $scope.doSomething = doA; 3 } 4 function ContentAreaController($scope) { 5 $scope.doSomething = doB; 6 }
請注意,到目前為止,我們所編寫的所有控制器中,都沒有在任何地方引用 DOM 或者 DOM 操作,所有定位元素和處理事件的工作都是在 Angular 內部完成的。
所以,你可以開心地使用 Angular 的宣告式事件處理器,同時又能保持簡單性和可讀性,沒有必要為違反最佳實踐而感到內疚。