Angular開發者指南(二)概念概述

template(模板):帶有附加標記的模板HTML
directives(指令):使用自定義屬性和元素擴展HTML
model(模型):用戶在視圖中顯示的數據,並與用戶進行交互
scope(做用域):存儲模型的上下文,以便控制器,指令和表達式能夠訪問它
expressions(表達式):訪問範圍中的變量和函數
compiler(編譯器):解析模板並實例化指令和表達式
filter(過濾器):格式化表達式的值以顯示給用戶
view(視圖):用戶看到的內容(DOM)
Data Binding(數據綁定):在模型和視圖之間同步數據
controller(控制器):視圖後面的業務邏輯
Dependency Injection:建立並鏈接對象和函數
injector(注入器):依賴注入容器
module(模塊):一個用於應用程序不一樣部分的容器,包括控制器,服務,過濾器,配置Injector的指令
service (服務):可重用的業務邏輯獨立於視圖
第一個例子:數據綁定
在下面的示例中,咱們將構建一個表單來計算不一樣貨幣的發票成本。
讓咱們從數量和成本的輸入字段開始,其值相乘以產生髮票總額:html

<div ng-app ng-init="qty=1;cost=2">
  <b>Invoice:</b>
  <div>
    Quantity: <input type="number" min="0" ng-model="qty">
  </div>
  <div>
    Costs: <input type="number" min="0" ng-model="cost">
  </div>
  <div>
    <b>Total:</b> {{qty * cost | currency}}
  </div>
</div>

這看起來像正常的HTML,有一些新的標記。 在AngularJS中,像這樣的文件稱爲模板。 當AngularJS啓動你的應用程序時,它使用編譯器從模板解析和處理這個新的標記。 加載,轉換和渲染的DOM而後稱爲視圖。
第一種新的標記是指令。 它們對HTML中的屬性或元素應用特殊的行爲。 在上面的例子中,咱們使用ng-app屬性,它連接到一個自動初始化咱們的應用程序的指令。 AngularJS還定義了一個爲元素添加額外行爲的輸入元素的指令。 ng-model指令存儲/更新輸入字段的值到/自變量。
訪問DOM的自定義指令:在AngularJS中,應用程序應該訪問DOM的惟一位置是指令內。 這很重要,由於訪問DOM的工件難以測試。 若是你須要直接訪問DOM,你應該爲它寫一個自定義指令。
第二種新的標記是雙花括號{{expression | filter}}:當編譯器遇到這個標記時,它將用標記的估計值替換它。 模板中的表達式是一個相似JavaScript的代碼片斷,它容許AngularJS讀取和寫入變量。 請注意,這些變量不是全局變量。 就像JavaScript函數中的變量存在於做用域中同樣,AngularJS爲表達式可訪問的變量提供了一個做用域。 存儲在做用域上的變量中的值在文檔的其他部分中稱爲模型。 應用於上面的示例,標記指示AngularJS「獲取從輸入小部件獲取的數據並將它們相乘」。
上面的示例還包含一個過濾器。 過濾器格式化表達式的值以顯示給用戶。 在上面的示例中,過濾器貨幣將數字格式化爲看起來像金錢的輸出。
在示例中重要的是,AngularJS提供活動綁定:每當輸入值更改時,表達式的值都會自動從新計算,並使用其值更新DOM。 這背後的概念是雙向數據綁定。
添加UI邏輯:控制器express

invoice1.jsjson

angular.module('invoice1', [])
.controller('InvoiceController', function InvoiceController() {
  this.qty = 1;
  this.cost = 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.qty * this.cost, this.inCurr, outCurr);
  };
  this.convertCurrency = function convertCurrency(amount, inCurr, outCurr) {
    return amount * this.usdToForeignRates[outCurr] / this.usdToForeignRates[inCurr];
  };
  this.pay = function pay() {
    window.alert('Thanks!');
  };
});

index.html後端

<div ng-app="invoice1" ng-controller="InvoiceController as invoice">
  <b>Invoice:</b>
  <div>
    Quantity: <input type="number" min="0" ng-model="invoice.qty" required >
  </div>
  <div>
    Costs: <input type="number" min="0" ng-model="invoice.cost" required>
    <select ng-model="invoice.inCurr">
      <option ng-repeat="c in invoice.currencies">{{c}}</option>
    </select>
  </div>
  <div>
    <b>Total:</b>
    <span ng-repeat="c in invoice.currencies">
      {{invoice.total(c) | currency:c}}
    </span><br>
    <button class="btn" ng-click="invoice.pay()">Pay</button>
  </div>
</div>

首先,有一個包含控制器的新JavaScript文件。更準確地說,該文件指定將用於建立實際控制器實例的構造函數。控制器的目的是將變量和功能暴露給表達式和指令。
除了包含控制器代碼的新文件,咱們還向HTML添加了ng-controller指令。這個指令告訴AngularJS,新的InvoiceController負責具備指令的元素和全部元素的子元素。語法InvoiceController做爲憑證告訴AngularJS實例化控制器並將其保存在當前做用域中的變量invoice 中。
咱們還更改了頁面中的全部表達式,以便在控制器實例中讀取和寫入變量,方法是在它們前面加上invoice 。 。可能的貨幣在控制器中定義,並使用ng-repeat添加到模板。因爲控制器包含一個總函數,咱們還可使用{{invoice.total(...)}}將該函數的結果綁定到DOM。
再次,這種綁定是活的,即,當函數的結果改變時,DOM將被自動更新。用於支付發票的按鈕使用指令ngClick。這將在每次點擊按鈕時評估相應的表達式。
在新的JavaScript文件中,咱們還建立了一個模塊,咱們在其中註冊控制器。咱們將在下一節中討論模塊。
下圖顯示了在咱們介紹控制器以後,一切是如何協同工做的:
圖片描述設計模式

獨立於視圖的業務邏輯:服務service
如今,InvoiceController包含咱們示例的全部邏輯。 當應用程序增加時,將與視圖無關的邏輯從控制器移動到服務中是一個好的作法,所以它也能夠由應用程序的其餘部分重用。 稍後,咱們還能夠更改該服務以從網絡(例如網絡)載入匯率。 經過調用Yahoo Finance API,而無需更改控制器。
讓咱們重構咱們的例子,並將貨幣轉換轉換爲另外一個文件中的服務:api

finance2.js數組

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

  return {
    currencies: currencies,
    convert: convert
  };
});

invoice2.js服務器

angular.module('invoice2', ['finance2'])
.controller('InvoiceController', ['currencyConverter', function InvoiceController(currencyConverter) {
  this.qty = 1;
  this.cost = 2;
  this.inCurr = 'EUR';
  this.currencies = currencyConverter.currencies;

  this.total = function total(outCurr) {
    return currencyConverter.convert(this.qty * this.cost, this.inCurr, outCurr);
  };
  this.pay = function pay() {
    window.alert('Thanks!');
  };
}]);

index.html網絡

<div ng-app="invoice2" ng-controller="InvoiceController as invoice">
  <b>Invoice:</b>
  <div>
    Quantity: <input type="number" min="0" ng-model="invoice.qty" required >
  </div>
  <div>
    Costs: <input type="number" min="0" ng-model="invoice.cost" required >
    <select ng-model="invoice.inCurr">
      <option ng-repeat="c in invoice.currencies">{{c}}</option>
    </select>
  </div>
  <div>
    <b>Total:</b>
    <span ng-repeat="c in invoice.currencies">
      {{invoice.total(c) | currency:c}}
    </span><br>
    <button class="btn" ng-click="invoice.pay()">Pay</button>
  </div>
</div>

咱們將convertCurrency函數和現有貨幣的定義移動到新文件finance2.js中。可是控制器如何保持如今分離的功能?
這是依賴注入發揮做用的地方。依賴注入(DI)是一種軟件設計模式,它處理對象和函數如何建立以及如何得到它們的依賴。 AngularJS中的全部內容(指令,過濾器,控制器,服務,...)都是使用依賴注入建立和鏈接的。在AngularJS中,DI容器稱爲注入器。
要使用DI,須要一個地方,全部應該一塊兒工做的東西都註冊。在AngularJS中,這是模塊的目的。當AngularJS啓動時,它將使用具備由ng-app指令定義的名稱的模塊配置,包括該模塊所依賴的全部模塊的配置。
在上面的示例中:模板包含指令ng-app =「invoice2」。這告訴AngularJS使用invoice2模塊做爲應用程序的主模塊。代碼片斷angular.module('invoice2',['finance2'])指定invoice2模塊依賴於finance2模塊。經過這個,AngularJS使用InvoiceController以及currencyConverter服務。
如今AngularJS知道應用程序的全部部分,它須要建立它們。在上一節中,咱們看到控制器是使用構造函數建立的。對於服務,有多種方式指定如何建立它們(請參閱服務指南)。在上面的例子中,咱們使用一個匿名函數做爲currencyConverter服務的工廠函數。此函數應返回currencyConverter服務實例。
回到最初的問題:InvoiceController如何得到對currencyConverter函數的引用?在AngularJS中,這是經過簡單地定義參數的構造函數。這樣,注入器可以以正確的順序建立對象,而且將先前建立的對象傳遞到依賴於它們的對象的工廠中。在咱們的示例中,InvoiceController有一個名爲currencyConverter的參數。經過這個,AngularJS知道控制器和服務之間的依賴關係,並以服務實例做爲參數來調用控制器。
在上一節和本節之間的示例中,最後一件事情是改變了,如今咱們將一個數組傳遞給module.controller函數,而不是一個簡單的函數。數組首先包含控制器須要的服務依賴關係的名稱。數組中的最後一個條目是控制器構造函數。 AngularJS使用這個數組語法來定義依賴關係,以便DI也能夠在縮小代碼後工做,這極可能會將控制器構造函數的參數名稱從新命名爲更短的。
圖片描述app

訪問後端
讓咱們經過從Yahoo Finance API獲取匯率來完成咱們的示例。 如下示例說明如何使用AngularJS完成此操做:

invoice3

angular.module('invoice3', ['finance3'])
.controller('InvoiceController', ['currencyConverter', function InvoiceController(currencyConverter) {
  this.qty = 1;
  this.cost = 2;
  this.inCurr = 'EUR';
  this.currencies = currencyConverter.currencies;

  this.total = function total(outCurr) {
    return currencyConverter.convert(this.qty * this.cost, this.inCurr, outCurr);
  };
  this.pay = function pay() {
    window.alert('Thanks!');
  };
}]);

finance3.js

angular.module('finance3', [])
.factory('currencyConverter', ['$http', function($http) {
  var YAHOO_FINANCE_URL_PATTERN =
        '//query.yahooapis.com/v1/public/yql?q=select * from ' +
        'yahoo.finance.xchange where pair in ("PAIRS")&format=json&' +
        'env=store://datatables.org/alltableswithkeys';
  var currencies = ['USD', 'EUR', 'CNY'];
  var usdToForeignRates = {};

  var convert = function(amount, inCurr, outCurr) {
    return amount * usdToForeignRates[outCurr] / usdToForeignRates[inCurr];
  };

  var refresh = function() {
    var url = YAHOO_FINANCE_URL_PATTERN.
               replace('PAIRS', 'USD' + currencies.join('","USD'));
    return $http.get(url).then(function(response) {
      var newUsdToForeignRates = {};
      angular.forEach(response.data.query.results.rate, function(rate) {
        var currency = rate.id.substring(3,6);
        newUsdToForeignRates[currency] = window.parseFloat(rate.Rate);
      });
      usdToForeignRates = newUsdToForeignRates;
    });
  };

  refresh();

  return {
    currencies: currencies,
    convert: convert
  };
}]);

index.html

<div ng-app="invoice3" ng-controller="InvoiceController as invoice">
  <b>Invoice:</b>
  <div>
    Quantity: <input type="number" min="0" ng-model="invoice.qty" required >
  </div>
  <div>
    Costs: <input type="number" min="0" ng-model="invoice.cost" required >
    <select ng-model="invoice.inCurr">
      <option ng-repeat="c in invoice.currencies">{{c}}</option>
    </select>
  </div>
  <div>
    <b>Total:</b>
    <span ng-repeat="c in invoice.currencies">
      {{invoice.total(c) | currency:c}}
    </span><br>
    <button class="btn" ng-click="invoice.pay()">Pay</button>
  </div>
</div>

咱們的financeConverter服務的財務模塊如今使用$ http,AngularJS提供的內置服務訪問服務器後端。 $ http是XMLHttpRequest和JSONP傳輸的包裝器。

相關文章
相關標籤/搜索