在 Angular 中实现搜索关键字高亮示例


Posted in Javascript onMarch 21, 2017

在 Angular 中,我们不应该试图直接修改 DOM 的内容,当需要更新 DOM 内容的时候,应该修改的其实是我们的数据模型,也就是 $scope 中的数据,Angular 会帮助我们将修改之后的数据展示在页面中。

但是,在有些情况下,比如我们有一个搜索框,希望将搜索的关键字在正文中高亮出来,这时候就会感觉比较吃力了,filter 可以帮助我们处理这种情况。

实际上,很多时候,我们的数据是不能直接输出到 DOM 中的,典型的比如日期,或者货币等等,通常需要将我们内部的数据格式化之后,再输出到页面中,在 Angular 中,这个工作就是通过 filter 来实现的。

filter 是 module 级别的服务,定义之后,可以在整个 module 内直接使用,有着极高的复用性。

为了说明问题,先回顾一下的 走进AngularJs(七) 过滤器(filter) 说明一下过滤器,然后详细说明如何处理搜索关键字高亮问题。你可以直接从自定义过滤器部分开始。

1. 过滤器的用法

1. 模板中使用

我们可以直接在{{}}中使用filter,跟在表达式后面用 | 分割,语法如下:

{{ expression | filter }}

也可以多个filter连用,上一个filter的输出将作为下一个filter的输入。

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

filter可以接收参数,参数用 : 进行分隔。

{{ expression | filter:argument1:argument2:... }}

除了对{{}}中的数据进行格式化,我们还可以在指令中使用filter,例如先对数组array进行过滤处理,然后再循环输出:

<span ng-repeat="a in array | filter ">

2. 在 controller 和 service 中使用

我们的js代码中也可以使用过滤器,方式就是我们熟悉的依赖注入,例如我要在controller中使用currency过滤器,只需将它注入到该controller中即可。

app.controller('testC',function($scope,currencyFilter){
  $scope.num = currencyFilter(123534); 
}

在模板中使用{{num}}就可以直接输出 $123,534.00了!在服务中使用filter也是同样的道理。

此时你可能会有疑惑,如果我要在controller中使用多个filter,难道要一个一个注入吗,这岂不太费劲了?小兄弟莫着急~ng提供了一个$filter服务可以来调用所需的filter,你只需注入一个$filter就够了,使用方法如下:

app.controller('testC',function($scope,$filter){
  $scope.num = $filter('currency')(123534);
$scope.date = $filter('date')(new Date()); 
}

2. 内置的 filter

1. currentcy, 使用currency可以将数字格式化为货币,默认是美元符号,你可以自己传入所需的符号

{{num | currency : '¥'}}

2. date, 原生的js对日期的格式化能力有限,ng提供的date过滤器基本可以满足一般的格式化要求。

{{date | date : 'yyyy-MM-dd hh:mm:ss EEEE'}}

3. filter, 注意了,这个过滤器的名字叫 filter,不要搞混了。用来处理一个数组,然后可以过滤出含有某个子串的元素,作为一个子数组来返回。可以是字符串数组,也可以是对象数组。如果是对象数组,可以匹配属性的值。它接收一个参数,用来定义子串的匹配规则。

$scope.childrenArray = [
    {name:'kimi',age:3},
    {name:'cindy',age:4},
    {name:'anglar',age:4},
    {name:'shitou',age:6},
    {name:'tiantian',age:5}
  ];

自定义的辅助函数。

$scope.func = function(e){return e.age>4;}

使用 filter 过滤器

{{ childrenArray | filter : 'a' }} //匹配属性值中含有a的
{{ childrenArray | filter : 4 }} //匹配属性值中含有4的
{{ childrenArray | filter : {name : 'i'} }} //参数是对象,匹配name属性中含有i的
{{childrenArray | filter : func }} //参数是函数,指定返回age>4的

4. json, 格式化 json 对象。json过滤器可以把一个js对象格式化为json字符串。作用就和我们熟悉的JSON.stringify()一样。

{{ jsonTest | json}}

5. limitTo, limitTo过滤器用来截取数组或字符串,接收一个参数用来指定截取的长度。只能从数组或字符串的开头进行截取

{{ childrenArray | limitTo : 2 }} //将会显示数组中的前两项

6. lowercase, 转换为小写。把数据转化为全部小写。

7. uppercase, 转换为大写。

8. number, 格式化数字。number过滤器可以为一个数字加上千位分割,像这样,123,456,789。同时接收一个参数,可以指定小float类型保留几位小数:

{{ num | number : 2 }}

9. orderBy 排序,orderBy过滤器可以将一个数组中的元素进行排序,接收一个参数来指定排序规则,参数可以是一个字符串,表示以该属性名称进行排序。可以是一个函数,定义排序属性。还可以是一个数组,表示依次按数组中的属性值进行排序(若按第一项比较的值相等,再按第二项比较),

<div>{{ childrenArray | orderBy : 'age' }}</div>   //按age属性值进行排序
<div>{{ childrenArray | orderBy : orderFunc }}</div>  //按照函数的返回值进行排序
<div>{{ childrenArray | orderBy : ['age','name'] }}</div> //如果age相同,按照name进行排序

3. 自定义 filter

 我们先定义个没有参数的过滤器。第一个例子来自 Angular 官方的文档。

我们希望检查数据是否为真,如果为真的话,显示为一个 ✓ ,否则的话,显示为  ✘, 在 Unicode 中,\u2713 -> ✓, \u2718 -> ✘,所以,我们需要做的就是检查数据是否为真,然后转化为这两个特殊字符进行输出。

app.filter('checkmark', function() {
 return function(input) {
  return input ? '\u2713' : '\u2718';
 };
});

过滤器还可以有参数,比如内置的过滤器可以格式话货币或者日期。

在过滤器后面,使用冒号 (:) 分隔的就是过滤器的参数,在过滤器中,可以获取这个参数,如果有多个参数,就继续使用冒号 (:) 进行分隔,所以,过滤器可以有多个参数。

下面实现一个截断超长字符串的过滤器。

app.filter("truncate", function(){
  return function(text, length){
    if (text) {
      var ellipsis = text.length > length ? "..." : "";
      return text.slice(0, length) + ellipsis;
    };
    return text;    
  }
});

4. 定义高亮 filter

 我们希望搜索的关键字在正文中高亮出来,正文就是过滤器的第一个参数,第二个参数就是搜索关键字,这样,我们的过滤器将会有两个参数了。

高亮的原理很简单,将需要高亮的内容使用 span 标记隔离出来,再加上一个特殊的 class 进行描述就可以了。

app.filter("highlight", function($sce, $log){

  var fn = function(text, search){
    $log.info("text: " + text);
    $log.info("search: " + search);

    if (!search) {
      return $sce.trustAsHtml(text);
    }
    text = encodeURI(text);
    search = encodeURI(search);

    var regex = new RegExp(search, 'gi')
    var result = text.replace(regex, '<span class="highlightedText">$&</span>');
    result = decodeURI(result);
    $log.info("result: " + result );
    return $sce.trustAsHtml(result);
  };

  return fn;
});

$sce, 和 $log 是 angular 提供的两个服务,其中 $sce 服务需要使用  ngSanitize 模块。关于这个模块,可以参考:angular-ngSanitize模块-$sanitize服务详解

5. 定义服务对象

我们的页面可能很复杂,需要在一个控制器中输入关键字,但是,需要在多个控制器中使用这个关键字进行过滤,怎么处理呢?使用服务可以解决这个问题。

在 Angular 中,服务就是一个单例对象,我们使用 factory 可以直接定义一个服务对象。

app.factory("notifyService", function(){
  var target = {
    search:"key"
  };

  return target;
});

在需要使用这个对象的地方,直接注入就可以获取这个对象了。

6. 定义搜索 Controller

在搜索控制器中,我们希望用户提供搜索关键字。为了方便检查,我们顺便将用户的输入展示出来。

<div ng-controller="tools">
      <div>
        <input type="text" ng-model="notify.search" value=""/>
      </div>
      <div>
        {{notify.search}}
      </div>
    </div>

控制器的实现,我们将服务对象直接注入到控制器中,然后绑定到当前的 $scope 上,以便在当前控制器中实现绑定。

app.controller("tools", function($scope, notifyService){
  $scope.notify = notifyService;
});

现在,我们可以直接输入搜索关键字,这个关键字将被保存到服务对象中,可以在当前的 module 中的各个控制器中访问这个服务对象。

7. 在内容 Controller 中使用 filter

现在,我们已经有了过滤器,也可以直接通过服务对象来获取搜索关键字,现在组合起来就可以使用了。text 中是我们的正文内容。

<div ng-controller="search">
      <div ng-bind-html="text | highlight:notify.search">
      </div>
    </div>

下面再看看 highlight 和 notify.search 来自何方。

app.controller("search", function($scope, $log, notifyService){
  $scope.text = "hello, world. hello, world. hello, world.";
  $scope.notify = notifyService;
})

为了在当前控制器中使用搜索关键字,关键是在搜索关键字发生变化的时候,还需要自动更新,我们将服务对象绑定到当前的 $scope 中,这是引用的名称为 notify.

这样,在复杂页面中,我们可能存在多个控制器,在每个需要高亮的控制器中,我们只需要注入服务对象,就可以直接获取到当前的搜索关键字,配合使用过滤器,就可以直接实现全局高亮了。

8. 总结

结合过滤器和服务对象,我们实现了在复杂页面中,对整个页面中的内容进行关键字高亮。以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
动态的改变IFrame的高度实现IFrame自动伸展适应高度
Dec 28 Javascript
使用GruntJS链接与压缩多个JavaScript文件过程详解
Aug 02 Javascript
Javascript表格翻页效果实现思路及代码
Aug 23 Javascript
JavaScript中获取样式的原生方法小结
Oct 08 Javascript
ECMAScript 5中的属性描述符详解
Mar 02 Javascript
基于jQuery+PHP+Mysql实现在线拍照和在线浏览照片
Sep 06 Javascript
微信小程序 特效菜单抽屉效果实例代码
Jan 11 Javascript
在Vant的基础上封装下拉日期控件的代码示例
Dec 05 Javascript
javaScript把其它类型转换为Number类型
Oct 13 Javascript
JavaScript异步操作的几种常见处理方法实例总结
May 11 Javascript
详解Typescript 内置的模块导入兼容方式
May 31 Javascript
Vue中使用import进行路由懒加载的原理分析
Apr 01 Vue.js
js省市区级联查询(插件版&amp;无插件版)
Mar 21 #Javascript
Bootstrap学习笔记 轮播(Carousel)插件
Mar 21 #Javascript
详解Vue2+Echarts实现多种图表数据可视化Dashboard(附源码)
Mar 21 #Javascript
node安装--linux下的快速安装教程
Mar 21 #Javascript
Vue 单文件中的数据传递示例
Mar 21 #Javascript
js实现颜色阶梯渐变效果(Gradient算法)
Mar 21 #Javascript
详解Vue 实例中的生命周期钩子
Mar 21 #Javascript
You might like
PHP脚本的10个技巧(5)
2006/10/09 PHP
详细解读PHP中接口的应用
2015/08/12 PHP
对于Laravel 5.5核心架构的深入理解
2018/02/22 PHP
tp5.1 框架join方法用法实例分析
2020/05/26 PHP
Javascript-Mozilla和IE中的一个函数直接量的问题分析
2007/08/12 Javascript
事件模型在各浏览器中存在差异
2010/10/20 Javascript
模拟jQuery ajax服务器端与客户端通信的代码
2011/03/28 Javascript
Jquery下:nth-child(an+b)的使用注意
2011/05/28 Javascript
用js小类库获取浏览器的高度和宽度信息
2012/01/15 Javascript
JS调用CS里的带参方法实例
2013/08/01 Javascript
JQuery触发事件例如click
2013/09/11 Javascript
JQuery实现table行折叠效果以JSON做数据源
2014/05/26 Javascript
JavaScript人脸识别技术及脸部识别JavaScript类库Tracking.js
2015/09/14 Javascript
js实现页面跳转的五种方法推荐
2016/03/10 Javascript
javascript弹出窗口中增加确定取消按钮
2016/06/24 Javascript
利用jQuery对无序列表排序的简单方法
2016/10/16 Javascript
在node.js中怎么屏蔽掉favicon.ico的请求
2017/03/01 Javascript
vue.js利用Object.defineProperty实现双向绑定
2017/03/09 Javascript
js获取浏览器的各种属性
2017/04/27 Javascript
vue解决弹出蒙层滑动穿透问题的方法
2018/09/22 Javascript
[46:03]LGD vs VGJ.T 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
寻找网站后台地址的python脚本
2014/09/01 Python
python中pycurl库的用法实例
2014/09/30 Python
Python3调用微信企业号API发送文本消息代码示例
2017/11/10 Python
EM算法的python实现的方法步骤
2018/01/02 Python
tensorflow 恢复指定层与不同层指定不同学习率的方法
2018/07/26 Python
社区版pycharm创建django项目的方法(pycharm的newproject左侧没有项目选项)
2020/09/23 Python
css3实现一款模仿iphone样式的注册表单
2013/03/20 HTML / CSS
世界领先的豪华床上用品供应商之一:Bedeck Home
2019/03/18 全球购物
泰国的头号网上婴儿用品店:Motherhood.co.th
2019/04/09 全球购物
公共汽车、火车和飞机票的通用在线预订和销售平台:INFOBUS
2019/11/30 全球购物
办公室秘书岗位职责范本
2014/02/11 职场文书
2015年幼儿园后勤工作总结
2015/04/25 职场文书
项目备案申请报告
2015/05/15 职场文书
SqlServer数据库远程连接案例教程
2021/07/15 SQL Server
python的netCDF4批量处理NC格式文件的操作方法
2022/03/21 Python