angular学习(十)—— Filter


过滤器将表达式的运算结果格式化后呈现给用户,可以用于视图模版,控制器或者服务。angularjs有一些内置的过滤器,如果想自己自定义也很容易。

过滤器

在视图模版中使用过滤器

过滤器可以用于视图模版中的表达式,语法如下:

1
{{ expression | filter }}

例如,{ { 12 | currency } }将数字12用currency过滤器格式化为货币输出,最后的结果为$12.00

angularjs的过滤器也支持过滤链,语法如下:

1
{{ expression | filter1 | filter2 | ... }}

过滤器还能支持参数输入,语法如下:

1
{{ 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数据,或者过滤器的表达式需要改变时)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<!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)。

下面的例子是一个反转字符串的过滤器,并且根据参数可以选择大小写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<!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循环都好执行一次或多次过滤器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<!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>

上面的例子转化为无状态过滤器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<!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>
文章目录
  1. 1. 过滤器
    1. 1.1. 在视图模版中使用过滤器
    2. 1.2. 过滤器的运行
    3. 1.3. 在控制器, 服务和指令中使用过滤器
    4. 1.4. 自定义过滤器
    5. 1.5. 状态过滤器
|