angularjs入門學習【應用剖析中篇】

   在上一節講完了關於應用開發中如數據綁定,添加樣式一類的基礎操作後,接下來,將在應用中,與控制其有關的一些事件。。。


一、UI和控制器的分離

我們需要明確控制器在應用中的三個作用:

【1】在應用模型中設置初始狀態

【2】通過$scope對象向視圖(UI模版)暴露函數和模型

【3】監視模型發生變化的其他部分並做出相應的動作


二、發佈scope中的數據模型

 傳遞給控制器的$scope對象是一種用來向視圖暴露模型數據的機制。在我們構建的應用中可能有其他數據,但是通過scope傳遞這些屬性時,angular只考慮模型部分。

 在之前的荔枝中,我們經常看到$scope構建的數據實例,而這一過程是在控制器中完成,在這裏,我們也可以通過一些間接的方法從模版建立模型。


1.使用表達式:由於表達式在可它們關聯的控制器中執行,所以在表達式中設置屬性和控制器中設置屬性是一致的。即可以如下這麼做

<button ng-click='count=3'>Set count to three</button>

其等同於

<div ng-controller='CountController'>
<button ng-click='setCount()'>Set count to three</button>
</div>

控制器定義

function CountController($scope) {
$scope.setCount = function() {
$scope.count=3;
}
}

2.通過ng-model進行一個數據綁定


三、用$watch觀察模型變化

$watch(watchFn, watchAction, deepWatch)
該函數每個參數詳細內容

watchFn:這個參數是angualr表達式字符串或返回監控模型的當前值的函數,該表達式會被執行多次

watchAction:這是一個函數或者表達式,當watchFn變化時將調用他們,函數形式而言,它有watchFn的新舊值,及一個$scope引用,函數前面function(newValue,oldValue,scope)

deepWatch:這是一個可選的布爾參數,如果設置成true,angualr將監視對象每個屬性的變化


接下的栗子是之前購物車的升級版

<div ng-controller="CartController">
<div ng-repeat="item in items">
<span>{{item.title}}</span>
<input ng-model="item.quantity">
<span>{{item.price | currency}}</span>
<span>{{item.price * item.quantity | currency}}</span>
</div>
<div>Total: {{totalCart() | currency}}</div>
<div>Discount: {{bill.discount | currency}}</div>
<div>Subtotal: {{subtotal() | currency}}</div>
</div>
CartController:

function CartController($scope) {
$scope.bill = {};
$scope.items = [
{title: 'Paint pots', quantity: 8, price: 3.95},
{title: 'Polka dots', quantity: 17, price: 12.95},
{title: 'Pebbles', quantity: 5, price: 6.95}
];
$scope.totalCart = function() {
var total = 0;
for (var i = 0, len = $scope.items.length; i < len; i++) {
total = total + $scope.items[i].price * $scope.items[i].quantity;
}
return total;
}
$scope.subtotal = function() { return $scope.totalCart() - $scope.bill.discount;
};
function calculateDiscount(newValue, oldValue, scope) {
$scope.bill.discount = newValue > 100 ? 10 : 0;
}
$scope.$watch($scope.totalCart, calculateDiscount);
}

注意:在totalCart()建立一個監視,totalCart()用於計算該支付的總額,每當其發生變化時,watch函數就會調用calculateDiscount(),然後我們設置對這個值適當的折扣。如果總值達昱100$,就設置折扣爲10$,否則爲0;

上述結果



對於watch性能,我們還需要注意一些潛在的性能問題

在上述例子中,雖然其能夠正常的運行,但如果我們在totoalCart()加一個調試的斷電,你將會看到它被調用了六次才渲染頁面,而在代碼中我們很容易跟蹤到三次,

1.模版中{{totalCart|currency}}

2.Subtotal()函數

3.$watch()函數

而angualr爲了驗證傳遞的模型變化已經完全傳遞,會再運行多一次,所以總共執行六次,而這種情況很容易造成一個循環依賴。所以我們提供了以下的集中解決辦法

一種是在數組的每個元素上創建愛你$watch監控變化,不過這樣只是僅僅計算了$scope屬性中的total,discount,subtotal

<div>Total: {{bill.total | currency}}</div>
<div>Discount: {{bill.discount | currency}}</div>
<div>Subtotal: {{bill.subtotal | currency}}</div>

然後在控制器中,我們監視數組的元素,一旦數組發生任何變化,均會調用函數重新計算總價

function CartController($scope) {
$scope.bill = {};
$scope.items = [
{title: 'Paint pots', quantity: 8, price: 3.95},
{title: 'Polka dots', quantity: 17, price: 12.95},
{title: 'Pebbles', quantity: 5, price: 6.95}
];
var calculateTotals = function() {
var total = 0;
for (var i = 0, len = $scope.items.length; i < len; i++) {
total = total + $scope.items[i].price * $scope.items[i].quantity;
}
$scope.bill.totalCart = total;
$scope.bill.discount = total > 100 ? 10 : 0;
$scope.bill.subtotal = total - $scope.bill.discount;
};
$scope.$watch('items', calculateTotals, true);
}

注意:在$scope指定了一個字符串的items,items將作爲表達式在調用它的$scope作用域中執行

然後由於我們監視數組中的所有項,angualar不得不對它進行一份拷貝用於對比,如果遇到一個具有很多元素的列表時,可能會導致運行效率降低

所以我們可以給$watch只傳一個用於重新計算屬性的watchFn


$scope.$watch(function() {
var total = 0;
for (var i = 0; i < $scope.items.length; i++) {
total = total + $scope.items[i].price * $scope.items[i].quantity;
}
$scope.bill.totalCart = total;
$scope.bill.discount = total > 100 ? 10 : 0;
$scope.bill.subtotal = total - $scope.bill.discount;
});

四、組織模塊的注入:


函數 定義
provider(name,object OR constructor()) 可配置,有複雜邏輯的服務,可用於構造函數
factory(name,$getFunction()) 不可配置,有複雜邏輯的服務,定義一個函數,調用時返回服務實例
service(name,constructor()) 具有簡單邏輯,用於創建服務實例

在這裏,我們利用之前討論過的items示例使用factory()

// Create a module to support our shopping views
var shoppingModule = angular.module('ShoppingModule', []);
// Set up the service factory to create our Items interface to the
// server-side database 
shoppingModule.factory('Items', function() {
var items = {};
items.query = function() {
// In real apps, we'd pull this data from the server... 
return [
{title: 'Paint pots', description: 'Pots full of paint', price: 3.95}, {title: 'Polka dots', description: 'Dots with polka’, price: 2.95},
{title: 'Pebbles', description: 'Just little rocks', price: 6.95}
];
};
return items;
});

<html ng-app='ShoppingModule'>
<body ng-controller="ShoppingController">
<h1>Shop!</h1>
<table> <tr ng-repeat=”item in items”></tr>
<td>{{item.title}}</td>
<td>{{item.description}}</td>
<td>{{item.price | currency}}</td>
</tr>
</table>
</div>

五、用過濾器過濾數據

過濾器允許你申明如何展示給用戶的數據轉換後插入到你的模版中。

{{ expression | filterName : parameter1 : ...parameterN }}

其中expression爲任意表達式,filterName爲你想用的過濾器的名稱,傳遞給過濾器的參數用冒號隔開,

而angular有幾個自帶過濾器如:date,number,uppercase等,在這裏就不多介紹,主要我們來學習如果自己創建一個自定義過濾器

下面例子是通過filter()函數構造一個名爲titleCase的過濾器,其作用是將句子中每個單詞的首字母大寫

var homeModule = angular.module('HomeModule', []);
homeModule.filter('titleCase', function() {
var titleCaseFilter = function(input) {
var words = input.split(' ');
for (var i = 0; i < words.length; i++) {
words[i] = words[i].charAt(0).toUpperCase() + words[i].slice(1);
}
return words.join(' ');
};
return titleCaseFilter;
});

對應的HTML模版

<body ng-app='HomeModule' ng-controller="HomeController">
<h1>{{pageHeading | titleCase}}</h1>
</body>

通過控制器賦值給模型變量

function HomeController($scope) {
$scope.pageHeading = 'behold the majesty of your page title';
}

運行結果如下圖





發佈了42 篇原創文章 · 獲贊 1 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章