多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
本节中,我们将使用 过滤器(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> ~~~