在 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 相关文章推荐
jQuery 瀑布流 绝对定位布局(二)(延迟AJAX加载图片)
May 23 Javascript
js 调用父窗口的具体实现代码
Jul 15 Javascript
浅谈checkbox的一些操作(实战经验)
Nov 20 Javascript
js模拟hashtable的简单实例
Mar 06 Javascript
浅谈JavaScript中setInterval和setTimeout的使用问题
Aug 01 Javascript
javascript时间排序算法实现活动秒杀倒计时效果
Jan 28 Javascript
AngularJS指令用法详解
Nov 02 Javascript
BootstrapValidator实现注册校验和登录错误提示效果
Mar 10 Javascript
前端把html表格生成为excel表格的实例
Sep 19 Javascript
JS交互点击WKWebView中的图片实现预览效果
Jan 05 Javascript
JS动画实现回调地狱promise的实例代码详解
Nov 08 Javascript
微信小程序 腾讯地图显示偏差问题解决
Jul 27 Javascript
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
各种战术和打法的原创者
2020/03/04 星际争霸
php download.php实现代码 跳转到下载文件(response.redirect)
2009/08/26 PHP
php页面,mysql数据库转utf-8乱码,utf-8编码问题总结
2015/08/27 PHP
[原创]PHP实现逐行删除文件右侧空格的方法
2015/12/25 PHP
javascript indexOf函数使用说明
2008/07/03 Javascript
利用javascript移动div层-javascript 拖动层
2009/03/22 Javascript
判断客户端浏览器是否安装了Flash插件的多种方法
2010/08/11 Javascript
定时器(setTimeout/setInterval)调用带参函数失效解决方法
2013/03/26 Javascript
jQuery学习笔记(1)--用jQuery实现异步通信(用json传值)具体思路
2013/04/08 Javascript
jquery的ajax和getJson跨域获取json数据的实现方法
2014/02/04 Javascript
通过原生JS实现为元素添加事件的方法
2016/11/23 Javascript
Javascript this 函数深入详解
2016/12/13 Javascript
JQuery validate 验证一个单独的表单元素实例
2017/02/17 Javascript
快速搭建React的环境步骤详解
2017/11/06 Javascript
Vue中父子组件通讯之todolist组件功能开发
2018/05/21 Javascript
vue.js自定义组件实现v-model双向数据绑定的示例代码
2020/01/08 Javascript
[51:17]Mineski vs Secret 2019国际邀请赛淘汰赛 败者组 BO3 第一场 8.22
2019/09/05 DOTA
Python读取Word(.docx)正文信息的方法
2018/03/15 Python
Python使用Pickle模块进行数据保存和读取的讲解
2019/04/09 Python
在python plt图表中文字大小调节的方法
2019/07/08 Python
pytorch 模型的train模式与eval模式实例
2020/02/20 Python
python+selenium+chrome批量文件下载并自动创建文件夹实例
2020/04/27 Python
实例代码讲解Python 线程池
2020/08/24 Python
Python self用法详解
2020/11/28 Python
Web页面中八种创建多列等高(等高列布局)的实现技术
2012/12/24 HTML / CSS
HTML5的结构和语义(1):前言
2008/10/17 HTML / CSS
产品质量保证书
2014/04/29 职场文书
幼儿生日活动方案
2014/08/27 职场文书
平安家庭事迹材料
2014/12/20 职场文书
父亲节活动总结
2015/02/12 职场文书
项目经理岗位职责范本
2015/04/01 职场文书
2015年文明创建工作总结
2015/04/30 职场文书
小学运动会加油词
2015/07/18 职场文书
MYSQL 无法识别中文的永久解决方法
2021/06/03 MySQL
详解OpenCV曝光融合
2022/04/29 Python
Python安装及建立虚拟环境的完整步骤
2022/06/25 Servers