生活随笔
收集整理的這篇文章主要介紹了
前端做模糊搜索
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
我們先看一下效果圖:
這是搜索關鍵字cfg時,會自動匹配到config方法
同樣,我們再看另一個例子
通過關鍵字bi會匹配到好幾個結果
這個和一些編輯器的搜索功能很像,比如sublime text,不需要知道關鍵字的完整拼寫,只需要知道其中的幾個字母即可。
那么這個功能在前端我們如何去實現呢?
不考慮性能的話,我們可以用正則簡單實現如下:
把關鍵字拆分,加入(.?),如cfg最終為 (.?)(c)(.?)(f)(.?)(g)(.*?),然后拿這個正則去測試要搜索的列表,把符合要求的選項給拿出來即可
考慮到要高亮結果,我們還要生成對應的替換表達式,最后的函數如下
var escapeRegExp = /[\-#$\^*()+\[\]{}|\\,.?\s]/g;
var KeyReg = (key) => {var src = ['(.*?)('];var ks = key.split('');if (ks.length) {while (ks.length) {src.push(ks.shift().replace(escapeRegExp, '\\$&'), ')(.*?)(');}src.pop();}src.push(')(.*?)');src = src.join('');var reg = new RegExp(src, 'i');var replacer = [];var start = key.length;var begin = 1;while (start > 0) {start--;replacer.push('$', begin, '($', begin + 1, ')');begin += 2;}replacer.push('$', begin);info = {regexp: reg,replacement: replacer.join('')};return info;
};
調用KeyReg把關鍵字傳入,拿返回值的regexp去檢測搜索的列表,把符合的保存下來即可。
到目前為止我們只實現了搜索功能,按更優的體驗來講,在搜索結果中,要優先把相連匹配的放在首位,如bi關鍵字,要把bind結果放到beginUpdate前面。第二個截圖是有優化的地方的。
要完成這個功能,我們使用KeyReg返回值中的replacement,用它進行檢測,把結果中長度最長的放前面即可,這塊代碼以后有時間再補充
2018.5.31
今天重構了下,增加了結果排序,完整的代碼及使用示例如下
let Searcher = (() => {let escapeRegExp = /[\-#$\^*()+\[\]{}|\\,.?\s]/g;let escapeReg = reg => reg.replace(escapeRegExp, '\\$&');//groupLeft 與 groupRight是對結果進一步處理所使用的分割符,可以修改let groupLeft = '(',groupRight = ')';let groupReg = new RegExp(escapeReg(groupRight + groupLeft), 'g');let groupExtractReg = new RegExp('(' + escapeReg(groupLeft) + '[\\s\\S]+?' + escapeReg(groupRight) + ')', 'g');//從str中找到最大的匹配長度let findMax = (str, keyword) => {let max = 0;keyword = groupLeft + keyword + groupRight;str.replace(groupExtractReg, m => {//keyword完整的出現在str中,則優秀級最高,排前面if (keyword == m) {max = Number.MAX_SAFE_INTEGER;} else if (m.length > max) {//找最大長度max = m.length;}});return max;};let keyReg = key => {let src = ['(.*?)('];let ks = key.split('');if (ks.length) {while (ks.length) {src.push(escapeReg(ks.shift()), ')(.*?)(');}src.pop();}src.push(')(.*?)');src = src.join('');let reg = new RegExp(src, 'i');let replacer = [];let start = key.length;let begin = 1;while (start > 0) {start--;replacer.push('$', begin, groupLeft + '$', begin + 1, groupRight);begin += 2;}replacer.push('$', begin);info = {regexp: reg,replacement: replacer.join('')};return info;};return {search(list, keyword) {//生成搜索正則let kr = keyReg(keyword);let result = [];for (let e of list) {//如果匹配if (kr.regexp.test(e)) {//把結果放入result數組中result.push(e.replace(kr.regexp, kr.replacement).replace(groupReg, ''));}}//對搜索結果進行排序//1. 匹配關鍵字大小寫一致的優先級最高,比如搜索up, 結果中的[user-page,beginUpdate,update,endUpdate],update要排在最前面,因為大小寫匹配//2. 匹配關鍵字長的排在前面result = result.sort((a, b) => findMax(b, keyword) - findMax(a, keyword));return result;}};
})();//假設list是待搜索的列表
let list = ['config', 'user-page', 'bind', 'render', 'beginUpdate', 'update', 'endUpdate'];
//假設userInput是用戶輸入的關鍵字
let userInput = 'up';//獲取搜索的結果
console.log(Searcher.search(list, userInput));
//?["(up)date", "begin(Up)date", "end(Up)date", "(u)ser-(p)age"]
對搜索結果中的內容做進一步處理渲染出來即可,比如把 ( 替換成 <span style="color:red"> 把 ) 替換成</span>顯示到頁面上就完成了高亮顯示
總結
以上是生活随笔為你收集整理的前端做模糊搜索的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。