本节中,我们将使用 过滤器(filter) 把手机详情中的true 与 false ,换成浏览体验更高的 <i style="color:green" class="icon icon-check"></i> 与 <i style="color:red" class="icon icon-cross"></i>
![](https://box.kancloud.cn/2016-08-03_57a1592050b9d.png)
# 找到两个图标
![](https://box.kancloud.cn/2016-08-03_57a1592068d7e.png)
对每天学习半小时v3.bootcss.com的我们,相应找到这两个图标的时间不会超过30S,如果你的时间超出了30S,那么说明你学习v3.bootcss.com的时间还不够。
> 简单的事情重复做,你就是专家;
重复的事情认真做,你就是赢家。
**重复,多么简单的事情,今天你做到了吗?**
# 认识过滤器
在前面的循环过滤器中,我们已经接触过了 过滤器。过滤器不仅实现 按过滤条件进行显示 的功能,还可以实现怎么显示、显示什么的功能。
在实际的项目中,比如对日期的格式化、对用户状态正常、冻结的格式化,对直接输出到页面的HTML的格式化,对金钱的格式化等等,我们将大量的与过滤器打交道。
下面,我们定义第一个过滤器,来实现false与true的人性化显示。
## 建立模块
由于过滤器往往会在多个项目中使用,或是说一旦有了过滤器,我们会使用在我们所涉及到的所有项目中。所以我们在此新建一个名为core的模块。
`core/core.module.js`
~~~
// 定义一个core模块,供模块内的组件使用。
angular.module('core', []);
~~~
## 建立过滤器
建立模块时,我们命名为xxx.module.js;建立组件时,我们命名为xxx.component.js;建立模板文件时,我们命名为xxx.template.js;同样,建立过滤器时,我们命名为xxx.filter.js
`core/checkmark/checkmark.filter.js`
有了说,老师为什么不是`core/checkmark.filter.js`而是`core/checkmark/checkmark.filter.js`,这当然是为了以后的扩展做准备了。
我们回想下建立component时的代码,再回想下配置路由的代码,照猫画虎(软件工程中叫做 抽象),我想大概我们也能猜出这个filter需要怎样定义了。
1 基本结构
~~~
angular.
module('core').
filter();
~~~
2 添加参数
~~~
angular.
module('core').
// 第一个参数是过滤器名,第二个参数是功能函数
filter('checkmark', function(){});
~~~
3 扩充功能代码
在过滤器的功能代码中,会直接返回一个 function , 然后模板在调用filter时,将原值值入filter, filter经过内部的函数处理后,将处理的结果返回给模板.
~~~
angular.
module('core').
// 第一个参数是过滤器名,第二个参数是功能函数
filter('checkmark', function(){
// input为模板传入的变量
return function(input){};
});
~~~
4 具体代码实现
我们简单的返回一个hello yunzhi试试
~~~
angular.
module('core').
// 第一个参数是过滤器名,第二个参数是功能函数
filter('checkmark', function(){
// input为模板传入的变量
return function(input){
return 'hello yunzhi';
};
});
~~~
这里面有两个return, 第一个return返回了一个function,此function供模板进行调用,并将模板中的变量做为参数(input)传入。第二个retrun,是将input进行处理后的返回值,该值将直接显示在模板中。
5 测试
我们在模板中加入过滤器,进行测试
5.1 引用JS文件
`index.html`
~~~
+ <script src="core/core.module.js"></script>
+ <script src="core/checkmark/checkmark.filter.js"></script>
~~~
5.2 注入core模块
`app.moudle.js`
~~~
// 定义模块
var phonecatApp = angular.module('phonecatApp', ['yunZhi', 'ngRoute', 'core']);
~~~
5.3 更改模板,加入过滤器
`yun-zhi/phone-detail.template.html`
~~~
<dt>Infrared</dt>
- <dd>{{$ctrl.phone.connectivity.infrared}}</dd>
+ <dd>{{$ctrl.phone.connectivity.infrared | checkmark}}</dd>
<dt>GPS</dt>
- <dd>{{$ctrl.phone.connectivity.gps}}</dd>
+ <dd>{{$ctrl.phone.connectivity.gps | checkmark}}</dd>
~~~
![](https://box.kancloud.cn/2016-08-03_57a1592080aad.png)
没错,我们看到以前的false和true就变成hello yunzhi了。
其实在这个过滤器中,我们并没有使用到模板的传入值。所以即使删除到input参数,也不会有任何的问题。当然了,既然是参数,那么名字也是可以更改的,所以我们更改为以下几种方式,都可以成功执行:
~~~
angular.
module('core').
// 第一个参数是过滤器名,第二个参数是功能函数
filter('checkmark', function(){
// input为模板传入的变量
return function(){
return 'hello yunzhi';
};
});
~~~
~~~
angular.
module('core').
// 第一个参数是过滤器名,第二个参数是功能函数
filter('checkmark', function(){
// input为模板传入的变量
return function(hello){
return 'hello yunzhi';
};
});
~~~
## 完善过滤器
我的目标,当true时输出<i style="color:green" class="icon icon-check"></i>,当false时,输出<i style="color:red" class="icon icon-cross"></i>。
~~~
angular.
module('core').
// 第一个参数是过滤器名,第二个参数是功能函数
filter('checkmark', function(){
// input为模板传入的变量
return function(input){
// 为true输出对号,否则,输出错号
if (input)
{
return '<i class="glyphicon glyphicon-ok"></i>';
} else {
return '<i class="glyphicon glyphicon-remove"></i>';
}
};
});
~~~
测试:
![](https://box.kancloud.cn/2016-08-03_57a159209a4a8.png)
?说好的<i style="color:green" class="icon icon-check"></i>去哪了?
我们说当显示的效果与我们的预期不同时,我们首先想到的应该是查看生成的源代码:
![](https://box.kancloud.cn/2016-08-03_57a15920b1c5f.png)
原来,我们返回html标记,被做为普通的字符串处理了。这是由于angularjs出于安全的角度考虑,当它接收到html标记语言时,会自动转化为普通的字符串,这样做的好处很明显:不会破坏模板的结构。
而当我们需要angularjs将返回文本做为html标记时,则需要调用一个叫做`Strict Contextual Escaping(严格的上下文模式)`内置服务模块,简写为sce,在angularjs中的名称为$sce。$sce中有一个方法叫做`$sce.trustAsHtml`, 译为:做为被信任的html文本。除此以外,还有trustAsUrl, trustAsResourceUrl, trustAsJs 和 trustAsCss
> angularjs内部定义的对象,都以$开头。$sce的详细说明, 我们可以在https://angular.org中,直接搜索来找到。当然了,其它的内置模块也一样。
## 加入$sce.trustAsHtml
~~~
module('core').
// 第一个参数是过滤器名,第二个参数是功能函数
filter('checkmark', function($sce){
// input为模板传入的变量
return function(input){
var result;
// 为true输出对号,否则,输出错号
if (input)
{
result = '<i class="glyphicon glyphicon-ok"></i>';
} else {
result = '<i class="glyphicon glyphicon-remove"></i>';
}
return $sce.trustAsHtml(result);
};
});
~~~
如果只在过滤器中,加入$sce.trustAsHtml,这还不够。我们还需要在模板中使用ng-bind-html来绑定这个可信的html标记:
`yun-zhi/phone-detail.template.html`
~~~
- <dd>{{$ctrl.phone.connectivity.infrared | checkmark}}</dd>
+ <dd ng-bind-html="$ctrl.phone.connectivity.infrared | checkmark"></dd>
...
~~~
测试:
![](https://box.kancloud.cn/2016-08-03_57a15920cd11a.png)
换成ng-bind-html后,我们想要的效果已经呈现在了我们面前。
## 代码重构
在开发中,将我们功能开发完毕后,下一步就是对代码重构。代码的重构能够增加易读性,大幅的减轻日后维护的压力。
`core/checkmark/checkmark.filter.js`
~~~
angular.
module('core').
// 第一个参数是过滤器名,第二个参数是功能函数
filter('checkmark', ['$sce', function($sce){
// input为模板传入的变量
return function(input){
var result = '<i class="glyphicon glyphicon-';
// 为true输出对号,否则,输出错号
if (input)
{
result += 'ok';
} else {
result += 'remove';
}
result += '"></i>'
// 引入$sce返回可信任的html标记
return $sce.trustAsHtml(result);
};
}]);
~~~
正如你看到了,为了避免代码压缩引起的问题,我将filter进行了改写。
* * * * *
`index.html`
~~~
<!DOCTYPE html>
<html lang="en" ng-app="phonecatApp">
<head>
<head>
<meta charset="UTF-8">
<title>hello</title>
<link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css">
<script src="bower_components/angular/angular.js"></script>
<script src="bower_components/angular-route/angular-route.js"></script>
<script src="app.moudle.js"></script>
<script src="app.config.js"></script>
<script src="yun-zhi/yun-zhi.module.js"></script>
<script src="yun-zhi/phone-list.component.js"></script>
<script src="yun-zhi/hello-yunzhi.component.js"></script>
<script src="yun-zhi/phone-detail.component.js"></script>
<script src="core/core.module.js"></script>
<script src="core/checkmark/checkmark.filter.js"></script>
</head>
<body>
<div ng-view></div>
</body>
</html>
~~~
`app.moudle.js`
~~~
// 定义模块
var phonecatApp = angular.module('phonecatApp', ['yunZhi', 'ngRoute', 'core']);
~~~
`core/core.module.js`
~~~
// 定义一个core模块,供模块内的组件使用。
angular.module('core', []);
~~~
`core/checkmark/checkmark.filter.js`
~~~
angular.
module('core').
// 第一个参数是过滤器名,第二个参数是功能函数
filter('checkmark', ['$sce', function($sce){
// input为模板传入的变量
return function(input){
var result = '<i class="glyphicon glyphicon-';
// 为true输出对号,否则,输出错号
if (input)
{
result += 'ok';
} else {
result += 'remove';
}
result += '"></i>'
// 引入$sce返回可信任的html标记
return $sce.trustAsHtml(result);
};
}]);
~~~
`yun-zhi/phone-detail.template.html`
~~~
<img ng-src="{{$ctrl.phone.images[0]}}" class="phone" />
<h1>{{$ctrl.phone.name}}</h1>
<p>{{$ctrl.phone.description}}</p>
<ul class="phone-thumbs">
<li ng-repeat="img in $ctrl.phone.images">
<img ng-src="{{img}}" />
</li>
</ul>
<ul class="specs">
<li>
<span>Availability and Networks</span>
<dl>
<dt>Availability</dt>
<dd ng-repeat="availability in $ctrl.phone.availability">{{availability}}</dd>
</dl>
</li>
<li>
<span>Battery</span>
<dl>
<dt>Type</dt>
<dd>{{$ctrl.phone.battery.type}}</dd>
<dt>Talk Time</dt>
<dd>{{$ctrl.phone.battery.talkTime}}</dd>
<dt>Standby time (max)</dt>
<dd>{{$ctrl.phone.battery.standbyTime}}</dd>
</dl>
</li>
<li>
<span>Storage and Memory</span>
<dl>
<dt>RAM</dt>
<dd>{{$ctrl.phone.storage.ram}}</dd>
<dt>Internal Storage</dt>
<dd>{{$ctrl.phone.storage.flash}}</dd>
</dl>
</li>
<li>
<span>Connectivity</span>
<dl>
<dt>Network Support</dt>
<dd>{{$ctrl.phone.connectivity.cell}}</dd>
<dt>WiFi</dt>
<dd>{{$ctrl.phone.connectivity.wifi}}</dd>
<dt>Bluetooth</dt>
<dd>{{$ctrl.phone.connectivity.bluetooth}}</dd>
<dt>Infrared</dt>
<dd ng-bind-html="$ctrl.phone.connectivity.infrared | checkmark"></dd>
<dt>GPS</dt>
<dd ng-bind-html="$ctrl.phone.connectivity.gps | checkmark"></dd>
</dl>
</li>
<li>
<span>Android</span>
<dl>
<dt>OS Version</dt>
<dd>{{$ctrl.phone.android.os}}</dd>
<dt>UI</dt>
<dd>{{$ctrl.phone.android.ui}}</dd>
</dl>
</li>
<li>
<span>Size and Weight</span>
<dl>
<dt>Dimensions</dt>
<dd ng-repeat="dim in $ctrl.phone.sizeAndWeight.dimensions">{{dim}}</dd>
<dt>Weight</dt>
<dd>{{$ctrl.phone.sizeAndWeight.weight}}</dd>
</dl>
</li>
<li>
<span>Display</span>
<dl>
<dt>Screen size</dt>
<dd>{{$ctrl.phone.display.screenSize}}</dd>
<dt>Screen resolution</dt>
<dd>{{$ctrl.phone.display.screenResolution}}</dd>
<dt>Touch screen</dt>
<dd ng-bind-html="$ctrl.phone.display.touchScreen | checkmark"></dd>
</dl>
</li>
<li>
<span>Hardware</span>
<dl>
<dt>CPU</dt>
<dd>{{$ctrl.phone.hardware.cpu}}</dd>
<dt>USB</dt>
<dd>{{$ctrl.phone.hardware.usb}}</dd>
<dt>Audio / headphone jack</dt>
<dd>{{$ctrl.phone.hardware.audioJack}}</dd>
<dt>FM Radio</dt>
<dd ng-bind-html="$ctrl.phone.hardware.fmRadio | checkmark"></dd>
<dt>Accelerometer</dt>
<dd ng-bind-html="$ctrl.phone.hardware.accelerometer | checkmark"></dd>
</dl>
</li>
<li>
<span>Camera</span>
<dl>
<dt>Primary</dt>
<dd>{{$ctrl.phone.camera.primary}}</dd>
<dt>Features</dt>
<dd>{{$ctrl.phone.camera.features.join(', ')}}</dd>
</dl>
</li>
<li>
<span>Additional Features</span>
<dd>{{$ctrl.phone.additionalFeatures}}</dd>
</li>
</ul>
~~~
- 前言
- 第一章:准备知识
- 第一节:GIT
- 第二节:Node.js
- 第三节:http-server
- 第四节:bower
- 第五节:firefox+chrome
- 第二章:官方示例教程
- 第零节:Hello Yunzhier
- 第一节:静态模板
- 第二节:MVC
- 回调函数
- 第三节:组件
- 第四节:重构组件
- 2.4.1 调用组件
- 2.4.2 规划目录结构
- 2.4.3 剥离V层
- 2.4.4 大话测试
- 第五节:循环过滤器
- 第六节:双向数据绑定
- 第七节:XHR与依赖注入
- 第八节:添加缩略图
- 第九节:模拟页面跳转
- 2.9.1 使用bower
- 2.9.2 使用grunt
- 第十节:完善手机详情页
- 第十一节:自定义过滤器
- 第十二节:行为处理
- 第十三节:封装请求
- 第十四节:应用动画
- 第十五节:总结
- 第三章:菜谱管理示例
- 第四章:总结