欢迎光临
我们一直在努力

Fuse.js 前端模糊搜索神器 - 从入门到精通

本文将详细介绍 Fuse.js 的使用方法,包含完整代码示例和参数详解。

前言

Fuse.js 是一个轻量级的 JavaScript 模糊搜索库,无需依赖任何外部库,支持浏览器和 Node.js 环境。它能够根据关键词对数据进行模糊匹配,并返回匹配度分数和匹配位置信息。

Fuse.js 应用场景

🎯 1. 大屏列表搜索

场景: 数据大屏、管理后台的表格搜索

// 用户在大屏中搜索产品名称
const fuse = new Fuse(products, { keys: ['name', 'code'], threshold: 0.3 })
// 实时过滤显示匹配的产品

📚 2. 离线文档和知识库

场景: 帮助中心、API 文档、内部知识库

// 搜索技术文档
const fuse = new Fuse(docs, { keys: ['title', 'content', 'tags'] })
// 用户输入"react hooks"即可找到相关文档

🧭 3. 系统菜单导航

场景: 后台管理系统的菜单快速定位

// 菜单搜索
const fuse = new Fuse(menus, {
keys: ['name', 'path', 'description'],
threshold: 0.4
})
// 输入"用户管理"或"user"都能找到用户管理菜单

🔍 4. 实时搜索建议

场景: 搜索框的下拉建议

// 输入时实时给出建议
const fuse = new Fuse(hotKeywords, { threshold: 0.2 })
const suggestions = fuse.search(query).slice(0, 5)

🛒 5. 电商商品搜索

场景: 商品列表模糊搜索

const fuse = new Fuse(products, {
keys: ['name', 'brand', 'category', 'description'],
threshold: 0.3,
includeScore: true
})
// "耐克运动鞋"可以匹配到"Nike运动鞋"

📝 6. 表单自动补全

场景: 地址输入、联系人选择

const fuse = new Fuse(addresses, {
keys: ['city', 'district', 'street'],
ignoreLocation: true
})

🎮 7. 游戏内搜索

场景: 游戏道具、技能、任务搜索

const fuse = new Fuse(gameItems, {
keys: ['name', 'description'],
threshold: 0.2
})

💼 8. 企业级应用

场景: CRM、ERP 系统中的客户、订单搜索

const fuse = new Fuse(customers, {
keys: ['name', 'company', 'email', 'phone'],
threshold: 0.3
})

📊 9. 数据分析工具

场景: 报表、指标、维度搜索

const fuse = new Fuse(metrics, {
keys: ['name', 'description', 'tags'],
threshold: 0.4
})

📱 10. 移动端应用

场景: App 内的搜索功能

// 移动端通常需要更宽松的匹配
const fuse = new Fuse(data, {
threshold: 0.5, // 更宽松
ignoreLocation: true
})

为什么选择 Fuse.js?

✅ 优势

  • 零依赖: 纯 JavaScript 实现
  • 轻量级: 体积小,性能好
  • 易用性: API 简单直观
  • 灵活性: 支持复杂配置
  • 功能强大: 支持高亮、排序、嵌套搜索

❌ 不适合的场景

  • 需要后端搜索(大数据量)
  • 需要模糊匹配图片、音频等二进制数据
  • 需要复杂的 SQL 查询

1. 安装与引入

NPM 安装

npm install fuse.js

CDN 引入

<script src="https://cdn.jsdelivr.net/npm/fuse.js@6.6.2"></script>

ES6 导入

import Fuse from 'fuse.js'

2. 基础使用

2.1 简单示例

// 1. 准备数据
const books = [
{ title: 'JavaScript 高级程序设计', author: 'Nicholas C. Zakas' },
{ title: '深入理解 ES6', author: 'Nicholas C. Zakas' },
{ title: 'Vue.js 实战', author: '梁灏' }
]

// 2. 创建 Fuse 实例
const fuse = new Fuse(books, {
keys: ['title', 'author']
})

// 3. 搜索
const results = fuse.search('JavaScript')
console.log(results)

2.2 输出结果

[
{
item: { title: 'JavaScript 高级程序设计', author: 'Nicholas C. Zakas' },
refIndex: 0,
score: 0.123,
matches: [
{
key: 'title',
value: 'JavaScript 高级程序设计',
indices: [[0, 9]] // 匹配位置:从0到9
}
]
}
]

3. 核心配置参数详解

3.1 keys – 搜索字段

类型: string[] 默认值: [] 说明: 指定要搜索的字段名,支持嵌套路径

const options = {
keys: ['title', 'author.name', 'tags']
}

3.2 threshold – 模糊度阈值

类型: number 默认值: 0.6 范围: 0.0 – 1.0 说明:

  • 0.0 = 完全匹配(严格)
  • 1.0 = 匹配任意内容(宽松)
  • 推荐值:0.3 – 0.4

const options = {
threshold: 0.3 // 适度模糊
}

3.3 includeScore – 包含匹配分数

类型: boolean 默认值: false 说明: 是否在结果中包含匹配度分数

const options = {
includeScore: true
}

3.4 includeMatches – 包含匹配信息

类型: boolean 默认值: false 说明: 是否包含详细的匹配位置信息(用于高亮)

const options = {
includeMatches: true
}

3.5 minMatchCharLength – 最小匹配字符长度

类型: number 默认值: 1 说明: 搜索关键词的最小字符数

const options = {
minMatchCharLength: 2 // 至少2个字符才搜索
}

3.6 shouldSort – 结果排序

类型: boolean 默认值: true 说明: 是否按匹配度分数排序(分数低的在前)

const options = {
shouldSort: true
}

3.7 useExtendedSearch – 扩展搜索模式

类型: boolean 默认值: false 说明: 启用后支持更多搜索语法

const options = {
useExtendedSearch: true
}

// 使用扩展搜索语法
fuse.search('\\'exact match') // 精确匹配
fuse.search('!term') // 排除 term

3.8 ignoreLocation – 忽略位置

类型: boolean 默认值: false 说明: 是否忽略关键词在文本中的位置

const options = {
ignoreLocation: true // 只要包含就匹配,不管位置
}

3.9 findAllMatches – 查找所有匹配

类型: boolean 默认值: false 说明: 是否查找所有匹配项(而不仅仅是第一个)

const options = {
findAllMatches: true
}

3.10 includeScore – 分数权重

类型: boolean 默认值: false 说明: 是否返回匹配分数

const options = {
includeScore: true
}

4. 完整配置示例

const options = {
// 搜索阈值:0.0(严格)- 1.0(宽松)
threshold: 0.3,

// 包含匹配分数
includeScore: true,

// 包含匹配信息(用于高亮)
includeMatches: true,

// 搜索字段
keys: ['title', 'description', 'tags', 'category'],

// 最小匹配字符长度
minMatchCharLength: 1,

// 是否排序
shouldSort: true,

// 忽略位置
ignoreLocation: false,

// 查找所有匹配
findAllMatches: false,

// 扩展搜索模式
useExtendedSearch: false
}

const fuse = new Fuse(data, options)

5. 实战案例:Vue 3 组件

5.1 完整组件代码

<template>
<div class="search-demo">
<h1>Fuse.js 模糊搜索演示</h1>

<!– 搜索输入 –>
<div class="search-box">
<input
v-model="searchQuery"
placeholder="输入关键词搜索…"
class="input"
/>

<!– 阈值控制滑块 –>
<div class="threshold-control">
<label>模糊度: {{ threshold.toFixed(2) }}</label>
<input
type="range"
v-model.number="threshold"
min="0"
max="1"
step="0.05"
/>
<span class="desc">{{ thresholdDescription }}</span>
</div>

<div class="stats">
找到 {{ results.length }} 条结果(共 {{ items.length }} 条)
</div>
</div>

<!– 搜索结果 –>
<div class="results" v-if="searchQuery">
<div v-for="result in results" :key="result.item.id" class="result-item">
<h3 v-html="highlight(result.item.title, result.matches, 'title')"></h3>
<p v-html="highlight(result.item.description, result.matches, 'description')"></p>
<div class="meta">
<span class="category">{{ result.item.category }}</span>
<span class="score">匹配度: {{ result.score.toFixed(2) }}</span>
</div>
<div class="tags">
<span
v-for="tag in result.item.tags"
:key="tag"
v-html="highlight(tag, result.matches, 'tags')"
></span>
</div>
</div>
</div>

<!– 原始数据 –>
<div class="original" v-else>
<h3>原始数据({{ items.length }} 条)</h3>
<div v-for="item in items" :key="item.id" class="item">
<h4>{{ item.title }}</h4>
<p>{{ item.description }}</p>
<div class="tags">
<span v-for="tag in item.tags" :key="tag">{{ tag }}</span>
</div>
</div>
</div>
</div>
</template>

<script>
import Fuse from 'fuse.js'

export default {
name: 'FuseDemo',
data() {
return {
searchQuery: '',
threshold: 0.3,
items: [
{
id: 1,
title: 'JavaScript 基础教程',
description: '学习 JavaScript 的基础知识,包括变量、函数和数据类型',
category: '编程',
tags: ['javascript', '基础', '教程']
},
{
id: 2,
title: 'Vue.js 实战技巧',
description: 'Vue.js 实际项目中的高级技巧和最佳实践分享',
category: '前端',
tags: ['vue', '实战', '技巧']
},
{
id: 3,
title: 'Node.js 性能优化',
description: '如何优化 Node.js 应用程序的性能和内存使用',
category: '后端',
tags: ['nodejs', '性能', '优化']
}
],
fuse: null
}
},
created() {
this.initFuse()
},
watch: {
threshold() {
this.initFuse() // 阈值改变时重新初始化
}
},
computed: {
// 阈值描述
thresholdDescription() {
if (this.threshold <= 0.1) return '精确匹配(严格)'
if (this.threshold <= 0.3) return '适度模糊(推荐)'
if (this.threshold <= 0.5) return '较模糊'
if (this.threshold <= 0.7) return '很模糊'
return '非常模糊(宽松)'
},

// 搜索结果
results() {
if (!this.searchQuery.trim()) return []
return this.fuse.search(this.searchQuery.trim())
}
},
methods: {
// 初始化 Fuse
initFuse() {
const options = {
threshold: this.threshold,
includeScore: true,
includeMatches: true,
keys: ['title', 'description', 'tags', 'category'],
minMatchCharLength: 1,
shouldSort: true
}
this.fuse = new Fuse(this.items, options)
},

// 高亮文本
highlight(text, matches, key) {
if (!matches || matches.length === 0) return text

const match = matches.find(m => m.key === key)
if (!match || !match.indices) return text

const indices = […match.indices].sort((a, b) => a[0] – b[0])
let result = ''
let lastIndex = 0

indices.forEach(([start, end]) => {
if (start < lastIndex) return

result += text.substring(lastIndex, start)
result += `<span class="highlight">${text.substring(start, end + 1)}</span>`
lastIndex = end + 1
})

result += text.substring(lastIndex)
return result
}
}
}
</script>

<style scoped>
.search-demo {
max-width: 800px;
margin: 0 auto;
padding: 20px;
}

.search-box {
background: #f8f9fa;
padding: 20px;
border-radius: 8px;
margin-bottom: 20px;
}

.input {
width: 100%;
padding: 12px 16px;
font-size: 16px;
border: 2px solid #ddd;
border-radius: 6px;
outline: none;
}

.input:focus {
border-color: #42b983;
}

.threshold-control {
margin-top: 15px;
padding: 10px;
background: white;
border-radius: 6px;
}

.threshold-control input[type="range"] {
width: 100%;
margin: 8px 0;
}

.threshold-control .desc {
color: #42b983;
font-weight: bold;
margin-left: 10px;
}

.stats {
margin-top: 10px;
color: #666;
font-size: 14px;
}

.result-item, .item {
background: white;
border: 1px solid #e9ecef;
border-radius: 6px;
padding: 16px;
margin-bottom: 12px;
}

.result-item h3, .item h4 {
margin: 0 0 8px 0;
color: #2c3e50;
}

.result-item p, .item p {
margin: 8px 0;
color: #555;
line-height: 1.6;
}

.meta {
display: flex;
justify-content: space-between;
margin-top: 8px;
font-size: 13px;
}

.category {
background: #e7f5ff;
color: #1971c2;
padding: 2px 8px;
border-radius: 4px;
}

.score {
color: #888;
font-style: italic;
}

.tags {
margin-top: 8px;
}

.tags span {
display: inline-block;
background: #42b983;
color: white;
padding: 3px 10px;
border-radius: 12px;
font-size: 11px;
margin-right: 6px;
margin-top: 4px;
}

/* 高亮样式 */
:deep(.highlight) {
background-color: #ff4444;
color: white;
padding: 2px 4px;
border-radius: 3px;
font-weight: bold;
}
</style>

fuse与传统js搜索对比

1.精准搜索 在这里插入图片描述

特性传统 JS 搜索(includes / RegExp)Fuse.js(模糊搜索引擎)
匹配精度 全等匹配,错一个字母就搜不到 模糊匹配,允许拼写错误、漏字
结果排序 无序,通常按原数组顺序排列 相关性排序,最像的结果排在最前面
搜索深度 需手写逻辑处理嵌套对象 支持路径配置,直接配置 author.name
业务逻辑 逻辑分散在各个 filter 中 声明式配置,通过权重、阈值统一控制

fuse可以通过调整模糊度扩大搜索范围,同一个搜索关键词,扩大模糊度搜索更多数据,其中会匹配单字情况 在这里插入图片描述

5.2 代码说明

  • 数据结构: 包含 id、title、description、category、tags
  • 动态阈值: 通过滑块实时调整模糊度
  • 高亮显示: 使用 Fuse.js 返回的 matches 信息进行关键词高亮
  • 实时搜索: 监听 threshold 变化,自动重新初始化 Fuse
  • 6. 高级用法

    6.1 嵌套对象搜索

    const data = [
    {
    id: 1,
    name: '公司名称',
    location: {
    city: '北京',
    address: '朝阳区'
    },
    tags: ['科技', 'AI']
    }
    ]

    const fuse = new Fuse(data, {
    keys: ['name', 'location.city', 'location.address', 'tags']
    })

    6.2 数组字段搜索

    const data = [
    { title: '文章1', tags: ['vue', 'javascript'] }
    ]

    const fuse = new Fuse(data, {
    keys: ['tags'] // 自动搜索数组中的每个元素
    })

    6.3 自定义匹配函数

    const options = {
    getFn: (obj, key) => {
    // 自定义获取值的逻辑
    return obj[key]
    }
    }

    6.4 扩展搜索模式

    const options = {
    useExtendedSearch: true
    }

    const fuse = new Fuse(data, options)

    // 搜索语法
    fuse.search('\\'exact phrase') // 精确短语
    fuse.search('!exclude') // 排除
    fuse.search('term1|term2') // 或

    7. 性能优化建议

    7.1 大数据集优化

    // 对于大数据集,预先创建索引
    const fuse = new Fuse(largeData, {
    threshold: 0.3,
    includeMatches: true
    })

    // 复用实例,避免重复创建

    7.2 搜索时机控制

    // 防抖搜索
    let timer = null
    watch(searchQuery, (newVal) => {
    clearTimeout(timer)
    timer = setTimeout(() => {
    results.value = fuse.search(newVal)
    }, 300)
    })

    7.3 限制返回结果

    const results = fuse.search(query)
    const limited = results.slice(0, 10) // 只取前10条

    8. 常见问题

    Q1: 如何处理中文搜索?

    A: Fuse.js 默认支持中文,无需特殊配置。

    Q2: 搜索速度慢怎么办?

    A:

  • 减少 keys 数量
  • 提高 threshold 值
  • 限制数据集大小
  • 使用防抖避免频繁搜索
  • Q3: 如何实现多关键词搜索?

    A:

    const query = 'vue javascript'
    const results = fuse.search(query)

    Q4: 如何清除搜索结果?

    A:

    if (!query.trim()) return []

    9. 完整参数速查表

    参数类型默认值说明
    keys string[] [] 搜索字段
    threshold number 0.6 模糊度 (0-1)
    includeScore boolean false 包含分数
    includeMatches boolean false 包含匹配信息
    minMatchCharLength number 1 最小匹配字符
    shouldSort boolean true 结果排序
    ignoreLocation boolean false 忽略位置
    findAllMatches boolean false 查找所有匹配
    useExtendedSearch boolean false 扩展搜索模式
    location number 0 匹配位置权重
    distance number 100 匹配距离
    maxPatternLength number 32 最大模式长度

    10. 总结

    Fuse.js 是一个功能强大且易用的模糊搜索库,适用于:

    • ✅ 搜索框实时搜索
    • ✅ 大屏列表筛选
    • ✅ 离线文档搜索
    • ✅ 系统菜单导航
    • ✅ 知识库检索

    通过合理配置参数,可以实现从精确到模糊的各种搜索需求,并提供良好的用户体验。

    相关资源

    • Fuse.js 官方文档
    • Fuse.js GitHub
    • Vue 3 官方文档

    如果这篇文章对你有帮助,欢迎点赞、收藏、关注! 🎉

    有问题欢迎在评论区交流讨论! 💬

    赞(0)
    未经允许不得转载:171主机测评 » Fuse.js 前端模糊搜索神器 - 从入门到精通
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址