Angular过滤器主要用来格式化输出表达式的值。过滤器可以用于视图模板、控制器或者服务组件中。我们可以通过Angular的api轻松的实现过滤器。
如何在模板中使用过滤器
我们可以通过如下语法在表达式中使用过滤器,类似于Linux命令行中的管道:
{{ expression | filter }}
例如:
{{ 12 | currency }} 将会以货币格式输出 $12.00, currency是Angular提供的过滤器。
还可以将多个过滤器联合使用,语法如下:
{{ expression | filter1 | filter2 | ... }}
过滤器可支持参数:
{{ expression | filter:argument1:argument2:... }}
例如:
{{ 1234 | number:2 }} 会将1234以精度为小数点后两位的格式输出: 1234.00.
如何在控制器、服务及指令中使用过滤器
我们可以通过依赖注入的方式(过滤器的名字格式为<filterName>Filter)在Angular组件中使用filter.例如注入number过滤器,则在组件的构造函数的参数中所声明的依赖的名字必须叫做numberFilter。 让我们通过具体示例来说明过滤器的用法:
<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>
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'); }]);在上面的控制器代码中,我们在构造方法长数组注入了filter依赖(controller('FilterController', ['filterFilter', function(filterFilter)). 接下来调用过滤器方法filterFilter(this.array, 'a')初始化了filteredArray属性,通过过滤器我们得到了含有"a"的所有名字。
相比于表达式, 我们可以在其他组件中控制对过滤器的调用,表达式中filter会在每次执行的时候都被执行一遍。
运行结果:
自定义过滤器
通过使用Angular api自己实现一个过滤器也很方便,只需在相应模块中通过filter工厂方法注册一个过滤器即可,Angular内部则通过filterProvider实现。 工厂方法中要求返回一个新的filter方法, 该方法的第一个参数为输入值即表达式中"|"号前面的输出。返回的filter方法通常具有无状态(stateless)和幂等(idempotent)性。filter的名字需符合angular表达式的命名规范,不允许出现连字符、点号等特殊字符。
让我们通过具体的例子来介绍如何自定义过滤器:
<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>
</div>
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', function($scope) { $scope.greeting = 'hello'; }]);
这个例子中我们实现了一个简单的过滤器reverse反顺序输出字符. 在module的filter方法中,第一个参数为过滤器的名字,第二个参数为一个函数,该函数返回了真正实现过滤逻辑的过滤器函数,接收两个参数,第一个参数为需要反转的字符串,第二参数用以判断是否需要转成大写。
在HTML模板的表达式中即可调用自定义的reverse过滤器: {{greeting|reverse}}, {{greeting|reverse:true}}。
运行结果:
有状态的过滤器
一般情况下,不推荐实现有状态的过滤器,因为这样做不能被angular优化执行,从而导致性能问题。可以通过将内部的状态变量移到控制器中并通过传参的形式将有状态的过滤器转换成无状态的。
如果的确需要实现带状态的过滤器则需将过滤器标记为$stateful,这也意味着过滤器会在每个$digest阶段可能被执行多次。
<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>
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: '*'});
在上面的代码中我们实现了decorate过滤器,并声明为带状态的(decorateFilter.$stateful = true;), 这样每次decoration.symbol发生变化是,该过滤器都会执行一遍, 过滤器中绑定了decoration值。
运行结果: