1. 程式人生 > >AngularJS基礎應用

AngularJS基礎應用

為了理解AngularJS的概念,這裡記錄下在網上學習AngularJS的幾個例子,並且快速接觸AngularJS的重要部分。

1、資料繫結

下面編寫一個表單,用來計算一個訂單在不同幣種下的總價。
首先,我們做一個單幣種表單,它有數量和單價兩個輸入框,並且把數量和單價相乘得出該訂單的總價格。

dataBinding.html -

<html ng-app>
<head>
<script src="js/angular.js"></script>
</head>
<body>
	<div ng-init="count=1;price=2">
		<b>訂單:</b>
		<div>
			數量: <input type="number" ng-model="count" required>
		</div>
		<div>
			單價: <input type="number" ng-model="price" required>
		</div>
		<div>
			<b>總價:{{count * price}}</b>
		</div>
	</div>
</body>
</html>

頁面展示 -
在這裡插入圖片描述
首先,我們來詳細講解一下這個HTML。這個HTML帶了一些新的標記,在Angular中叫做“模板”。當Angular啟動應用時,它通過“編譯器”來解析並處理模板中的這些標記。這些經過載入、轉換、渲染而成的DOM就叫做“檢視”。這一類新標記叫做“指令”。它們通過HTML中的屬性或元素來為頁面新增特定的行為。

ng-app指令
ng-app定義了AngularJS應用程式的根元素
ng-app在網頁載入完畢時會自動引導(自動初始化)應用程式。

ng-init指令
ng-init指令為AngularJS應用程式定義了初始值。
通常情況下,會使用控制器或模組來代替它。

ng-model指令


ng-model指令繫結HTML元素到應用程式資料。

{{expression | filter}}
expression是“表示式”語句,filter是“過濾器”語句。表示AngularJS資料繫結表示式。AngularJS中的資料繫結,同步了AngularJS表示式與AngularJS資料。{{count * price}}是通過ng-model="count"與ng-model=“price” 進行同步。




2、控制器

現在,新增一些邏輯,讓該例子支援不同的幣種。它將允許我們使用不同的幣種來輸入、計算和支付這個訂單。

controllerBinding.html

-

<html ng-app="invoice1">
  <head>
    <script src="js/angular.js"></script>
    <script src="js/invoice1.js"></script>
  </head>
  <body>
    <div ng-controller="InvoiceController as invoice">
      <b>訂單:</b>
      <div>
        數量: <input type="number" ng-model="invoice.count" required >
      </div>
      <div>
        單價: <input type="number" ng-model="invoice.price" required >
        <select ng-model="invoice.inCurr">
          <option ng-repeat="c in invoice.currencies" value="{{c}}">{{c}}</option>
        </select>
      </div>
      <div>
        <b>總價:</b><br/>
        <span ng-repeat="c in invoice.currencies">{{c}}{{invoice.total(c)}}<br/></span><br/>
        <button class="btn" ng-click="invoice.pay()">支付</button>
      </div>
    </div>
  </body>
</html>

invoice1.js -

angular.module('invoice1', [])
  .controller('InvoiceController', function() {
    this.count = 1;
    this.price = 2;
    this.inCurr = 'EUR';
    this.currencies = ['USD', 'EUR', 'CNY'];
    this.usdToForeignRates = {
      USD: 1,
      EUR: 0.74,
      CNY: 6.09
    };
 
    this.total = function total(outCurr) {
      return this.convertCurrency(this.count * this.price, this.inCurr, outCurr);
    };
    this.convertCurrency = function convertCurrency(amount, inCurr, outCurr) {
      return amount * this.usdToForeignRates[outCurr] * 1 / this.usdToForeignRates[inCurr];
    };
    this.pay = function pay() {
      window.alert("謝謝!");
    };
  });

頁面展示 -
在這裡插入圖片描述
看看這次發生了什麼變化?這裡增加了一個JavaScript檔案,它包含一個被稱為“控制器(controller)”的函式。其實,這個檔案相當於定義了一個建構函式,它用來在建立這個控制器函式的例項。控制器的用途是匯出一些變數和函式,供模板中的表示式指令使用。

ng-controller指令
ng-controller指令定義了應用程式控制器。控制器是JavaScript物件,由標準的JavaScript物件的建構函式建立。ng-controller="InvoiceController as invoice"屬性是一個AngularJS指令。用於定義一個控制器。InvoiceController as invoice是把InvoiceController例項賦值給當前作用域(Scope)中的invoice變數。

ng-repeat指令
ng-repeat指令對於集合中(陣列中)的每一項會克隆一次HTML元素。

ngClick指令
當它被點選時,自動執行invoice.pay()函式。




3、服務

現在,InvoiceController包含了這個例子所有的邏輯。如果這個應用程式的規模繼續擴大,最好的做法是:把控制器中與檢視無關的邏輯都移植到“服務(service)”中。以便程式可以複用這部分的邏輯。
接下來,就讓我們重構我們的例子,並且把幣種兌換的邏輯移入到一個獨立的服務(service)中。

serviceBinding.html -

<html ng-app="invoice2">
  <head>
    <script src="js/angular.js"></script>
    <script src="js/finance2.js"></script>
    <script src="js/invoice2.js"></script>
  </head>
  <body>
    <div ng-controller="InvoiceController as invoice">
      <b>訂單:</b>
      <div>
        數量: <input type="number" ng-model="invoice.count" required >
      </div>
      <div>
        單價: <input type="number" ng-model="invoice.price" required >
        <select ng-model="invoice.inCurr">
          <option ng-repeat="c in invoice.currencies" value="{{c}}">{{c}}</option>
        </select>
      </div>
      <div>
        <b>總價:</b><br/>
        <span ng-repeat="c in invoice.currencies">{{c}}{{invoice.total(c)}}<br/></span><br/>
        <button class="btn" ng-click="invoice.pay()">支付</button>
      </div>
    </div>
  </body>
</html>

finance2.js -

angular.module('finance2', [])
      .factory('currencyConverter', function() {
        var currencies = ['USD', 'EUR', 'CNY'],
            usdToForeignRates = {
          USD: 1,
          EUR: 0.74,
          CNY: 6.09
        };
        return {
          currencies: currencies,
          convert: convert
        };
     
        function convert(amount, inCurr, outCurr) {
          return amount * usdToForeignRates[outCurr] * 1 / usdToForeignRates[inCurr];
        }
      });

invoice2.js -

    angular.module('invoice2', ['finance2'])
      .controller('InvoiceController', ['currencyConverter', function(currencyConverter) {
        this.count = 1;
        this.price = 2;
        this.inCurr = 'EUR';
        this.currencies = currencyConverter.currencies;
     
        this.total = function total(outCurr) {
          return currencyConverter.convert(this.count * this.price, this.inCurr, outCurr);
        };
        this.pay = function pay() {
          window.alert("謝謝!");
        };
      }]);

頁面展示 -
在這裡插入圖片描述
這次有什麼改動?我們把convertCurrency(invoice1.js)函式和所支援的幣種獨立到一個新的檔案:finance2.js。但是控制器怎樣才能找到這個獨立的函式呢?
invoice1.js -

this.convertCurrency = function convertCurrency(amount, inCurr, outCurr) {
      return amount * this.usdToForeignRates[outCurr] * 1 / this.usdToForeignRates[inCurr];
};

這下該“依賴注入(Dependency Injection)”出場了。依賴注入(DI)是一種設計模式,它用於解決下列問題:我們建立了物件和函式,但是它們怎麼得到自己所依賴的物件呢?Angular中的每一樣東西都是用依賴注入(DI)的方式來建立和使用的,比如指令(Directive)、過濾器(Filter)、控制器(Controller)、服務(Service)。在Angular中,依賴注入(DI)的容器叫做“注入器(Injector)”。
要想進行依賴注入,你必須先把這些需要協同工作的物件和函式註冊(Register)到某個地方。在Angular中,這個地方叫做“模組(module)”。

在上面這個例子中: 模板包含了一個ng-app="invoice2"指令。這告訴Angular使用invoice2模組作為該應用程式的主模組。 像angular.module('invoice2', ['finance2'])這樣的程式碼告訴Angular:invoice2模組依賴於finance2模組。 這樣一來,Angular就能同時使用InvoiceController這個控制器和currencyConverter這個服務了。

剛才我們已經定義了應用程式的所有部分,現在,需要Angular來建立它們了。 在上一節,我們瞭解到控制器(controller)是通過一個工廠函式建立的。 而對於服務(service),則有多種方式來定義它們的工廠函式(參見服務指南)。 上面這個例子中,我們通過一個返回currencyConverter函式的函式作為建立currencyConverter服務的工廠。 (js中的“工廠(factory)”是指一個以函式作為“返回值”的函式

回到剛才的問題:InvoiceController該怎樣獲得這個currencyConverter函式的引用呢? 在Angular中,這非常簡單,只要在建構函式中定義一些具有特定名字的引數就可以了。 這時,注入器(injector)就可以按照正確的依賴關係建立這些物件,並且根據名字把它們傳入那些依賴它們的物件工廠中。 在我們的例子中,InvoiceController有一個叫做currencyConverter的引數。 根據這個引數,Angular就知道InvoiceController依賴於currencyConverter,取得currencyConverter服務的例項,並且把它作為引數傳給InvoiceController的建構函式。

這次改動中的最後一點是我們現在把一個數組作為引數傳入到module.controller函式中,而不再是一個普通函式。 這個陣列前面部分的元素包含這個控制器所依賴的一系列服務的名字,最後一個元素則是這個控制器的建構函式。 Angular可以通過這種陣列語法來定義依賴,以免js程式碼壓縮器(Minifier)破壞這個“依賴注入”的過程。 因為這些js程式碼壓縮器通常都會把建構函式的引數重新命名為很短的名字,比如a,而常規的依賴注入是需要根據引數名來查詢“被注入物件”的。 (譯註:因為字串不會被js程式碼壓縮器重新命名,所以陣列語法可以解決這個問題。)
在這裡插入圖片描述