共计 2529 个字符,预计需要花费 7 分钟才能阅读完成。
以前我总是这样过滤搜寻内容
data.filter(item => item.indexOf(keywords) >= 0)
这样的确能够满足关键字搜寻需要,但鉴于前端是间接出现画面给用户的人,咱们总是须要站在用户的角度去思考问题。前面我的项目做多了,其实发现这样在用户体验上并不够敌对,咱们来看下上面这个例子:
chrome 浏览器内编辑款式
vs code 内编辑款式
在 chrome 浏览器内无奈进行非间断的字符匹配,造成了一些体验感的缺失,而在 vs code 内却能够自在间断地输出关键字匹配。毫无疑问在 vs code 中咱们的编辑体验会更加晦涩,因为在很多场景下,咱们记不得一段间断的关键字,而是在断断续续的关键字,此时咱们应用这种间断的关键字进行搜寻能够很好地进步用户体验,而且也不影响间断的关键字搜寻。
什么场景下能够用非间断关键字搜寻
这类需要个别为搜寻本地数据时,且需要场景没有明确指定须要间断的关键字搜寻时,咱们都能够应用非间断关键字搜寻来实现,具体列举了以下几个场景:
- 树形菜单项搜寻:相似治理后盾页面的菜单、多节点搜寻
- checkbox 选项搜寻:选项较多的可搜寻 checkbox 内
- 门路列表搜寻:如 vs code 的文件搜寻
- 本地缓存搜寻:微信的缓存聊天记录关键字搜寻
接下来咱们探讨一下如何实现
得益于万能的npmjs.com
,经验百般搜寻,我在下面找到了一个不错的 js 函数库实现了非间断关键字搜寻,咱们先看一个简略的 Demo,再分析一下它的实现原理。
js 库在此 -> string-discontinuous-match
此 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 库给出了这样的答复:
在 10000 个 5000 位随机字符串中搜寻 50 位随机要害字符串,疏忽大小写,花了101ms
,性能好是不错的。
结尾
对于一个前端来说,咱们还是应该把用户体验放在重要的地位,而这个搜寻就是其中的优化点之一,只须要简略一步操作,咱们就能够解决此问题,不晓得正在看文章的你感觉是否值得一试呢?如果对这个 js 库感兴趣的能够自行钻研源码,其实它也很简略。
明天就到此啦,如有什么问题能够给作者去提 issue 哦。对我的教程感到称心,请不要悭吝你手中的收费赞赞哦!!!