前端使用模糊搜索fuse.js和拼音搜索pinyin-match提升搜索体验

纯前端搜索常规实现就是字符串匹配(includes/indexOf), 使用模糊搜索和拼音搜索可以让搜索体验更好,模糊搜索推荐 fuse.js,拼音搜索推荐 pinyin-match。这两个库都不大,pinyin-match 27KB,fuse.js 不到20KB,体积负担不重,比起引入一个庞大的拼音库轻量很多。

如果再能高亮匹配字符就更完美了。模糊搜索fuse.js可以直接字符正则匹配替换,拼音搜索pinyin-match会返回位置信息,根据位置信息截取字符串即可。

以下是针对 Vue3 的实现代码:

js 复制代码
let Fuse;
let Pinyin;

const searchValue = ref('');
const list = ref([]);

const searchList = computed(() => {
  list.value.forEach(item => (item.titleSearch = void 0));
  if (!searchValue.value) return list.value;

  try {
    // 模糊搜索
    const fuse = new Fuse(list.value, {
      keys: ['title'],
      threshold: 0.5,
    });
    const fuseList = fuse.search(searchValue.value).map(m => {
      m.item.titleSearch = m.item.title.replace(new RegExp(`[${searchValue.value}]`, 'gi'), s => `<span class="search-target">${s}</span>`);
      return m.item;
    });
    // 拼音搜索
    const pinyinList = list.value.filter(m => {
      if (fuseList.find(f => f.objId === m.objId)) return false;
      const match = Pinyin.match(m.title, searchValue.value);
      if (match) {
        console.log(m.title, match);
        m.titleSearch = `${m.title.slice(0, match[0])}<span class="search-target">${m.title.slice(match[0], match[1] + 1)}</span>${m.title.slice(
          match[1] + 1
        )}`;
      }
      return match;
    });

    return fuseList.concat(pinyinList);
  } catch (error) {
    console.log(error);
    return list.value.filter(f => f.title.toLowerCase().includes(searchValue.value.toLowerCase()));
  }
});

onMounted(() => {
  importSearchLib();
})

function importSearchLib() {
  // 模糊搜索库,异步加载
  import('fuse.js')
    .then(module => {
      Fuse = module.default;
    })
    .catch(err => {
      console.log(err);
    });
  // 拼音搜索库,异步加载
  import('pinyin-match')
    .then(module => {
      Pinyin = module.default;
    })
    .catch(err => {
      console.log(err);
    });
}
  • list.value.forEach(item => (item.titleSearch = void 0)); 用于提前声明增加响应式属性 titleSearch,该字段是含高亮匹配字符的富文本。

  • return list.value.filter(f => f.title.toLowerCase().includes(searchValue.value.toLowerCase())); 错误回退机制,如果 fuse.js 或 pinyin-match 使用中报错了,回退到常规的字符串匹配(includes/indexOf)搜索。

  • importSearchLib() 异步加载 fuse.jspinyin-match,虽然这两个库都不大,但搜索一般是用户主动触发,没必要在页面加载过程中引入,难免拖慢页面加载,上面的实现就是放到了 onMounted 钩子中等 DOM 装载完毕才去异步加载这两个库。

  • import('fuse.js') 如果出现如下语法格式化错误提醒:

Dynamic imports are only supported when the '--module' flag is set to 'es2020', 'es2022', 'esnext', 'commonjs', 'amd', 'system', 'umd', 'node16', 'node18', or 'nodenext'.ts-plugin(1323)

改一下 tsconfig.json 的配置即可:

json 复制代码
{
  "compilerOptions": {
    "module": "ES2020",
    "target": "ES2020",
  }
}
相关推荐
老前端的功夫2 分钟前
前端技术选型的理性之道:构建可量化的ROI评估模型
前端·javascript·人工智能·ubuntu·前端框架
狮子座的男孩14 分钟前
js函数高级:04、详解执行上下文与执行上下文栈(变量提升与函数提升、执行上下文、执行上下文栈)及相关面试题
前端·javascript·经验分享·变量提升与函数提升·执行上下文·执行上下文栈·相关面试题
爱学习的程序媛25 分钟前
《JavaScript权威指南》核心知识点梳理
开发语言·前端·javascript·ecmascript
乐观主义现代人1 小时前
go 面试
java·前端·javascript
1***Q7841 小时前
前端在移动端中的离线功能
前端
星环处相逢1 小时前
Nginx 优化与防盗链及扩展配置指南
服务器·前端·nginx
tsumikistep1 小时前
【前后端】Vue 脚手架与前端工程结构入门指南
前端·javascript·vue.js
在繁华处1 小时前
JAVA实战:文件管理系统1.0
java·开发语言·前端
GISer_Jing2 小时前
SSE Conf大会分享支付宝xUI引擎:AI时代的多模态交互革命
前端·人工智能·交互
Aerelin2 小时前
爬虫playwright中的资源监听
前端·爬虫·js·playwright