只需一步,让你的搜索框智能得起飞

以前我总是这样过滤搜索内容

data.filter(item => item.indexOf(keywords) >= 0)

这样确实可以满足关键字搜索需求,但鉴于前端是直接呈现画面给用户的人,我们总是需要站在用户的角度去考虑问题。后面项目做多了,其实发现这样在用户体验上并不够友好,我们来看下下面这个例子:

chrome浏览器内编辑样式

chrome.gif

vs code内编辑样式

vscode.gif

在chrome浏览器内无法进行非连续的字符匹配,造成了一些体验感的缺失,而在vs code内却可以自由间断地输入关键字匹配。毫无疑问在vs code中我们的编辑体验会更加流畅,因为在很多场景下,我们记不得一段连续的关键字,而是在断断续续的关键字,此时我们使用这种间断的关键字进行搜索可以很好地提高用户体验,而且也不影响连续的关键字搜索。

什么场景下可以用非连续关键字搜索

这类需求一般为搜索本地数据时,且需求场景没有明确指定需要连续的关键字搜索时,我们都可以使用非连续关键字搜索来实现,具体列举了以下几个场景:

  1. 树形菜单项搜索:类似管理后台页面的菜单、多节点搜索
  2. checkbox选项搜索:选项较多的可搜索checkbox内
  3. 路径列表搜索:如vs code的文件搜索
  4. 本地缓存搜索:微信的缓存聊天记录关键字搜索

接下来我们探讨一下如何实现

得益于万能的npmjs.com,经历百般搜索,我在上面找到了一个不错的js函数库实现了非连续关键字搜索,我们先看一个简单的Demo,再剖析一下它的实现原理。

js库在此 -> string-discontinuous-match

demo.gif

此Demo中在1000条长度为200的随机字符串中非连续关键字搜索,完成单次搜索只需要1-2ms,性能可观。

接下来贴一下实现代码,通过Vue实现

<div id="app">
  <div class="search-wrap">
    <label>🔍</label>
    <input class="search-box" v-model="val" @input="inputHandler" />
  </div>
  <div class="info">
    <span>Data totals: {{ numbers }}</span>
    <span v-if="performance">Performance: {{ performance }}</span>
  </div>
  <div class="result">
    <span class="item" v-for="item in strings" :key="item" v-html="item"></span>
  </div>
</div>
// 初始状态
data() {
  return {
    val: '',
    strings: strings,  // strings内包含1000条测试随机字符串
    numbers: strings.length,
    performance: '',
  };
}

以下为input事件实现

<input @input="inputHandler" />

import { discontinuousMatch, replaceMatchedString } from 'string-discontinuous-match';
function inputHandler() {
  // this.val为搜索关键字
  if (this.val) {
    let s = performance.now();
      let ret = discontinuousMatch(strings, this.val);
      let e = performance.now();
      this.strings = ret.map(item => {
        // 辅助函数replaceMatchedString
        return replaceMatchedString(item, chars => `<span class="keyword">${chars}</span>`);
      });
      this.performance = (e - s) + 'ms';
    }
    else {
      this.data = strings;
      this.strings = strings;
      this.performance = '';
    }
    this.numbers = this.strings.length;
  }

搜索结果格式为:

[
  {
    value: 'xxx',   // 被搜索的字符串
    index: 0,       // 该项在数组中的索引
    
    // 匹配的关键字索引位置,如[0, 2]表示value中下标为0-2(包含2)位置的字符,14表示下标为14的单个字符。
    position: [[0, 2], [10, 12], 14, 17],
    lastIndex: 17   // 最后一个匹配的索引
  },
  // ...
]

所以你可以通过position信息去高亮对应位置的字符,但实际上你并不需要自己处理,string-discontinuous-match为我们提供了一个辅助函数来处理它,例如在inputHandler函数中,你可以看到将匹配结果循环传入了replaceMatchedString函数中,它的作用是帮我们提取匹配到的字符串,它根据position数组依次触发回调,在position: [[0, 2], [10, 12], 14, 17]中会分别提取下标0到2的字符串,并触发一次回调,在回调中你可以返回转化后的字符串例如用<span>标签包裹它,接下来再提取10到12的字符串并触发回调,以此类推共计触发4次回调,最后把转化后的字符串返回给我们,这样我们就可以很方便地实现匹配关键字的高亮状态了。

通过这样一顿操作,就已经实现了非连续关键字搜索的功能了。

性能怎么样???

大家应该都会有这样的疑问,数据量小还好,但对于大数据量的匹配,会不会很慢呢?毕竟是非连续的匹配呢!!!
这个问题,此js库给出了这样的回答:

image.png

在10000个5000位随机字符串中搜索50位随机关键字符串,忽略大小写,花了101ms,性能好是不错的。

结尾

对于一个前端来说,我们还是应该把用户体验放在重要的位置,而这个搜索就是其中的优化点之一,只需要简单一步操作,我们就可以解决此问题,不知道正在看文章的你觉得是否值得一试呢?如果对这个js库感兴趣的可以自行研究源码,其实它也很简单。
今天就到此啦,如有什么问题可以给作者去提issue哦。对我的教程感到满意,请不要吝啬你手中的免费赞赞哦!!!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,451评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,172评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,782评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,709评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,733评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,578评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,320评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,241评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,686评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,878评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,992评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,715评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,336评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,912评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,040评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,173评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,947评论 2 355

推荐阅读更多精彩内容