angular學習(十)—— Filter
過濾器
過濾器將表示式的運算結果格式化後呈現給使用者,可以用於檢視模版,控制器或者服務。angularjs有一些內建的過濾器,如果想自己自定義也很容易。
在檢視模版中使用過濾器
過濾器可以用於檢視模版中的表示式,語法如下:
{{ expression | filter }}
例如,{{ 12 | currency }}
將數字12用currency過濾器格式化為貨幣輸出,最後的結果為$12.00
。
angularjs的過濾器也支援過濾鏈,語法如下:
{{ expression | filter1 | filter2 | ... }}
過濾器還能支援引數輸入,語法如下:
{{ expression | filter:argument1:argument2:... }}
例如{{ 1234 | number:2 }}
會將數字1234用number過濾器格式化,根據引數保留小數點後2位,結果為 1,234.00
過濾器的執行
檢視模版中的過濾器僅僅在輸入改變時才會執行,這比每一次$digest迴圈都執行一次要高效的多。
但也有兩種例外的情況:
- 通常只在輸入是基礎型別的過濾器才會在輸入改變時菜執行。如果過濾器對輸入是object的話,每次$digest過濾器都會執行,因為要監測object是否改變會更耗效能。
- 如果過濾器標記為$stateful,那麼也會在每次$digest都執行。
在控制器, 服務和指令中使用過濾器
你也可以在控制器,服務和指令中使用過濾器。
為此,需要將過濾器以<filterName>Filter
的語法注入到相應的controller/service/directive中。例如你想注入number
過濾器就是用numberFilter
,過濾器函式作為控制器的第一個引數注入,過濾器的引數作為控制器函式的第二個引數。
下面的例子所使用的過濾器叫做filter,這個過濾器接受一個數組,並根據過濾條件產生一個子陣列。如果在檢視模版中表示的話,可以寫成{{ctrl.array | filter:'a'}}
,將會對陣列以a為關鍵字進行全文搜尋。然而,如果在檢視模版中這樣做的話,它會在每次$digest都執行過濾器,這會非常耗費效能。因此下面的例子就將過濾器寫在了控制器中,只有在需要的時候才會呼叫(例如從後端load資料,或者過濾器的表示式需要改變時)
<!DOCTYPE html>
<html>
<head>
<meta charset="uft-8"/>
<title></title>
</head>
<script src="script/angular.min.js"></script>
<script>
angular.module('FilterInControllerModule', []).
controller('FilterController', ['filterFilter', function(filterFilter) {
this.array = [
{name: 'Tobias'},
{name: 'Jeff'},
{name: 'Brian'},
{name: 'Igor'},
{name: 'James'},
{name: 'Brad'}
];
this.filteredArray = filterFilter(this.array, 'a');
}]);
</script>
<body ng-app="FilterInControllerModule">
<div ng-controller="FilterController as ctrl">
<div>
All entries:
<span ng-repeat="entry in ctrl.array">{{entry.name}} </span>
</div>
<div>
Entries that contain an "a":
<span ng-repeat="entry in ctrl.filteredArray">{{entry.name}} </span>
</div>
</div>
</body>
</html>
自定義過濾器
自定義一個過濾器也相當容易,僅僅需要在module中註冊一個新的filter工廠函式。工廠函式會返回一個新的過濾器函式,過濾器的輸入作為過濾器函式的第一個引數,其他過濾器的引數作為過濾器函式的附加引數傳入。
過濾器函式是一個純函式,這意味著給出相同的輸入引數總能得到相同的輸出結果,而不受外界狀態的影響(例如,angularjs的services)。根據這一點,angularjs才能做到僅僅當輸入變化時才去執行一次過濾器。帶狀態帶過濾器也存在,但是非常低效。
過濾器的名字必須是有效的angularjs表示式識別符號,例如uppercase,orderBy。名字中不能帶有特殊字元,比如-
和.
都是不允許的,你可以用駱駝命名法(myappSubsectionFilterx
)或者下劃線代替(myapp_subsection_filterx
)。
下面的例子是一個反轉字串的過濾器,並且根據引數可以選擇大小寫:
<!DOCTYPE html>
<html>
<head>
<meta charset="uft-8"/>
<title></title>
</head>
<script src="script/angular.min.js"></script>
<script>
angular.module('myReverseFilterApp', [])
.filter('reverse', function() {
return function(input, uppercase) {
input = input || '';
var out = '';
for (var i = 0; i < input.length; i++) {
out = input.charAt(i) + out;
}
// conditional based on optional argument
if (uppercase) {
out = out.toUpperCase();
}
return out;
};
})
.controller('MyController', ['$scope', 'reverseFilter', function($scope, reverseFilter) {
$scope.greeting = 'hello';
$scope.filteredGreeting = reverseFilter($scope.greeting);
}]);
</script>
<body ng-app="myReverseFilterApp">
<div ng-controller="MyController">
<input ng-model="greeting" type="text"><br>
No filter: {{greeting}}<br>
Reverse: {{greeting|reverse}}<br>
Reverse + uppercase: {{greeting|reverse:true}}<br>
Reverse, filtered in controller: {{filteredGreeting}}<br>
</div>
</body>
</html>
狀態過濾器
強烈建議不要寫有狀態的過濾器,因為angularjs並不會對其做優化,常常會導致效能問題。很多狀態過濾器可以通過暴露模型的狀態並把它作為過濾器的引數傳入,來達到改為不帶狀態的過濾器。
如果你非要寫一個帶狀態帶過濾器,記得把過濾器標記為$stateful,這樣每次$digest迴圈都好執行一次或多次過濾器。
<!DOCTYPE html>
<html>
<head>
<meta charset="uft-8"/>
<title></title>
</head>
<script src="script/angular.min.js"></script>
<script>
angular.module('myStatefulFilterApp', [])
.filter('decorate', ['decoration', function(decoration) {
function decorateFilter(input) {
return decoration.symbol + input + decoration.symbol;
}
decorateFilter.$stateful = true;
return decorateFilter;
}])
.controller('MyController', ['$scope', 'decoration', function($scope, decoration) {
$scope.greeting = 'hello';
$scope.decoration = decoration;
}])
.value('decoration', {symbol: '*'});
</script>
<body ng-app="myStatefulFilterApp">
<div ng-controller="MyController">
Input: <input ng-model="greeting" type="text"><br>
Decoration: <input ng-model="decoration.symbol" type="text"><br>
No filter: {{greeting}}<br>
Decorated: {{greeting | decorate}}<br>
</div>
</body>
</html>
上面的例子轉化為無狀態過濾器:
<!DOCTYPE html>
<html>
<head>
<meta charset="uft-8"/>
<title></title>
</head>
<script src="script/angular.min.js"></script>
<script>
angular.module('myStatelessFilterApp', [])
.filter('decorate', function() {
function decorateFilter(input,symbol) {
return symbol + input + symbol;
}
decorateFilter.$stateful = true;
return decorateFilter;
})
.controller('MyController', ['$scope', function($scope) {
$scope.greeting = 'hello';
$scope.symbol="*";
}])
.value('decoration', {symbol: '*'});
</script>
<body ng-app="myStatelessFilterApp">
<div ng-controller="MyController">
Input: <input ng-model="greeting" type="text"><br>
Decoration: <input ng-model="symbol" type="text"><br>
No filter: {{greeting}}<br>
Decorated: {{greeting | decorate:symbol}}<br>
</div>
</body>
</html>
如果我的文章對您有幫助,請用支付寶打賞: