Fuse.js前端模糊搜索神器從入門到精通教程
本文將詳細(xì)介紹 Fuse.js 的使用方法,包含完整代碼示例和參數(shù)詳解。
前言
Fuse.js 是一個輕量級的 JavaScript 模糊搜索庫,無需依賴任何外部庫,支持瀏覽器和 Node.js 環(huán)境。它能夠根據(jù)關(guān)鍵詞對數(shù)據(jù)進(jìn)行模糊匹配,并返回匹配度分?jǐn)?shù)和匹配位置信息。
Fuse.js 應(yīng)用場景
1. 大屏列表搜索
場景: 數(shù)據(jù)大屏、管理后臺的表格搜索
// 用戶在大屏中搜索產(chǎn)品名稱
const fuse = new Fuse(products, { keys: ['name', 'code'], threshold: 0.3 })
// 實時過濾顯示匹配的產(chǎn)品
2. 離線文檔和知識庫
場景: 幫助中心、API 文檔、內(nèi)部知識庫
// 搜索技術(shù)文檔
const fuse = new Fuse(docs, { keys: ['title', 'content', 'tags'] })
// 用戶輸入"react hooks"即可找到相關(guān)文檔
3. 系統(tǒng)菜單導(dǎo)航
場景: 后臺管理系統(tǒng)的菜單快速定位
// 菜單搜索
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. 表單自動補全
場景: 地址輸入、聯(lián)系人選擇
const fuse = new Fuse(addresses, {
keys: ['city', 'district', 'street'],
ignoreLocation: true
})
7. 游戲內(nèi)搜索
場景: 游戲道具、技能、任務(wù)搜索
const fuse = new Fuse(gameItems, {
keys: ['name', 'description'],
threshold: 0.2
})
8. 企業(yè)級應(yīng)用
場景: CRM、ERP 系統(tǒng)中的客戶、訂單搜索
const fuse = new Fuse(customers, {
keys: ['name', 'company', 'email', 'phone'],
threshold: 0.3
})
9. 數(shù)據(jù)分析工具
場景: 報表、指標(biāo)、維度搜索
const fuse = new Fuse(metrics, {
keys: ['name', 'description', 'tags'],
threshold: 0.4
})
10. 移動端應(yīng)用
場景: App 內(nèi)的搜索功能
// 移動端通常需要更寬松的匹配
const fuse = new Fuse(data, {
threshold: 0.5, // 更寬松
ignoreLocation: true
})
為什么選擇 Fuse.js?
優(yōu)勢
- 零依賴: 純 JavaScript 實現(xiàn)
- 輕量級: 體積小,性能好
- 易用性: API 簡單直觀
- 靈活性: 支持復(fù)雜配置
- 功能強(qiáng)大: 支持高亮、排序、嵌套搜索
不適合的場景
- 需要后端搜索(大數(shù)據(jù)量)
- 需要模糊匹配圖片、音頻等二進(jìn)制數(shù)據(jù)
- 需要復(fù)雜的 SQL 查詢
1. 安裝與引入
NPM 安裝
npm install fuse.js
CDN 引入
<script src="https://cdn.jsdelivr.net/npm/fuse.js@6.6.2"></script>
ES6 導(dǎo)入
import Fuse from 'fuse.js'
2. 基礎(chǔ)使用
2.1 簡單示例
// 1. 準(zhǔn)備數(shù)據(jù)
const books = [
{ title: 'JavaScript 高級程序設(shè)計', author: 'Nicholas C. Zakas' },
{ title: '深入理解 ES6', author: 'Nicholas C. Zakas' },
{ title: 'Vue.js 實戰(zhàn)', author: '梁灝' }
]
// 2. 創(chuàng)建 Fuse 實例
const fuse = new Fuse(books, {
keys: ['title', 'author']
})
// 3. 搜索
const results = fuse.search('JavaScript')
console.log(results)
2.2 輸出結(jié)果
[
{
item: { title: 'JavaScript 高級程序設(shè)計', author: 'Nicholas C. Zakas' },
refIndex: 0,
score: 0.123,
matches: [
{
key: 'title',
value: 'JavaScript 高級程序設(shè)計',
indices: [[0, 9]] // 匹配位置:從0到9
}
]
}
]
3. 核心配置參數(shù)詳解
3.1 keys - 搜索字段
- 類型:
string[] - 默認(rèn)值:
[] - 說明: 指定要搜索的字段名,支持嵌套路徑
const options = {
keys: ['title', 'author.name', 'tags']
}
3.2 threshold - 模糊度閾值
- 類型:
number - 默認(rèn)值:
0.6 - 范圍:
0.0 - 1.0 - 說明:
0.0= 完全匹配(嚴(yán)格)1.0= 匹配任意內(nèi)容(寬松)- 推薦值:
0.3 - 0.4
const options = {
threshold: 0.3 // 適度模糊
}
3.3 includeScore - 包含匹配分?jǐn)?shù)
- 類型:
boolean - 默認(rèn)值:
false - 說明: 是否在結(jié)果中包含匹配度分?jǐn)?shù)
const options = {
includeScore: true
}
3.4 includeMatches - 包含匹配信息
- 類型:
boolean - 默認(rèn)值:
false - 說明: 是否包含詳細(xì)的匹配位置信息(用于高亮)
const options = {
includeMatches: true
}
3.5 minMatchCharLength - 最小匹配字符長度
- 類型:
number - 默認(rèn)值:
1 - 說明: 搜索關(guān)鍵詞的最小字符數(shù)
const options = {
minMatchCharLength: 2 // 至少2個字符才搜索
}
3.6 shouldSort - 結(jié)果排序
- 類型:
boolean - 默認(rèn)值:
true - 說明: 是否按匹配度分?jǐn)?shù)排序(分?jǐn)?shù)低的在前)
const options = {
shouldSort: true
}
3.7 useExtendedSearch - 擴(kuò)展搜索模式
- 類型:
boolean - 默認(rèn)值:
false - 說明: 啟用后支持更多搜索語法
const options = {
useExtendedSearch: true
}
// 使用擴(kuò)展搜索語法
fuse.search('\'exact match') // 精確匹配
fuse.search('!term') // 排除 term
3.8 ignoreLocation - 忽略位置
- 類型:
boolean - 默認(rèn)值:
false - 說明: 是否忽略關(guān)鍵詞在文本中的位置
const options = {
ignoreLocation: true // 只要包含就匹配,不管位置
}
3.9 findAllMatches - 查找所有匹配
- 類型:
boolean - 默認(rèn)值:
false - 說明: 是否查找所有匹配項(而不僅僅是第一個)
const options = {
findAllMatches: true
}
3.10 includeScore - 分?jǐn)?shù)權(quán)重
- 類型:
boolean - 默認(rèn)值:
false - 說明: 是否返回匹配分?jǐn)?shù)
const options = {
includeScore: true
}
4. 完整配置示例
const options = {
// 搜索閾值:0.0(嚴(yán)格)- 1.0(寬松)
threshold: 0.3,
// 包含匹配分?jǐn)?shù)
includeScore: true,
// 包含匹配信息(用于高亮)
includeMatches: true,
// 搜索字段
keys: ['title', 'description', 'tags', 'category'],
// 最小匹配字符長度
minMatchCharLength: 1,
// 是否排序
shouldSort: true,
// 忽略位置
ignoreLocation: false,
// 查找所有匹配
findAllMatches: false,
// 擴(kuò)展搜索模式
useExtendedSearch: false
}
const fuse = new Fuse(data, options)
5. 實戰(zhàn)案例:Vue 3 組件
5.1 完整組件代碼
<template>
<div class="search-demo">
<h1>Fuse.js 模糊搜索演示</h1>
<!-- 搜索輸入 -->
<div class="search-box">
<input
v-model="searchQuery"
placeholder="輸入關(guān)鍵詞搜索..."
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 }} 條結(jié)果(共 {{ items.length }} 條)
</div>
</div>
<!-- 搜索結(jié)果 -->
<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>
<!-- 原始數(shù)據(jù) -->
<div class="original" v-else>
<h3>原始數(shù)據(jù)({{ 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 基礎(chǔ)教程',
description: '學(xué)習(xí) JavaScript 的基礎(chǔ)知識,包括變量、函數(shù)和數(shù)據(jù)類型',
category: '編程',
tags: ['javascript', '基礎(chǔ)', '教程']
},
{
id: 2,
title: 'Vue.js 實戰(zhàn)技巧',
description: 'Vue.js 實際項目中的高級技巧和最佳實踐分享',
category: '前端',
tags: ['vue', '實戰(zhàn)', '技巧']
},
{
id: 3,
title: 'Node.js 性能優(yōu)化',
description: '如何優(yōu)化 Node.js 應(yīng)用程序的性能和內(nèi)存使用',
category: '后端',
tags: ['nodejs', '性能', '優(yōu)化']
}
],
fuse: null
}
},
created() {
this.initFuse()
},
watch: {
threshold() {
this.initFuse() // 閾值改變時重新初始化
}
},
computed: {
// 閾值描述
thresholdDescription() {
if (this.threshold <= 0.1) return '精確匹配(嚴(yán)格)'
if (this.threshold <= 0.3) return '適度模糊(推薦)'
if (this.threshold <= 0.5) return '較模糊'
if (this.threshold <= 0.7) return '很模糊'
return '非常模糊(寬松)'
},
// 搜索結(jié)果
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與傳統(tǒng)js搜索對比
1.精準(zhǔn)搜索

| 特性 | 傳統(tǒng) JS 搜索(includes / RegExp) | Fuse.js(模糊搜索引擎) |
|---|---|---|
| 匹配精度 | 全等匹配,錯一個字母就搜不到 | 模糊匹配,允許拼寫錯誤、漏字 |
| 結(jié)果排序 | 無序,通常按原數(shù)組順序排列 | 相關(guān)性排序,最像的結(jié)果排在最前面 |
| 搜索深度 | 需手寫邏輯處理嵌套對象 | 支持路徑配置,直接配置 author.name |
| 業(yè)務(wù)邏輯 | 邏輯分散在各個 filter 中 | 聲明式配置,通過權(quán)重、閾值統(tǒng)一控制 |
fuse可以通過調(diào)整模糊度擴(kuò)大搜索范圍,同一個搜索關(guān)鍵詞,擴(kuò)大模糊度搜索更多數(shù)據(jù),其中會匹配單字情況

5.2 代碼說明
- 數(shù)據(jù)結(jié)構(gòu): 包含 id、title、description、category、tags
- 動態(tài)閾值: 通過滑塊實時調(diào)整模糊度
- 高亮顯示: 使用 Fuse.js 返回的 matches 信息進(jìn)行關(guān)鍵詞高亮
- 實時搜索: 監(jiān)聽 threshold 變化,自動重新初始化 Fuse
6. 高級用法
6.1 嵌套對象搜索
const data = [
{
id: 1,
name: '公司名稱',
location: {
city: '北京',
address: '朝陽區(qū)'
},
tags: ['科技', 'AI']
}
]
const fuse = new Fuse(data, {
keys: ['name', 'location.city', 'location.address', 'tags']
})
6.2 數(shù)組字段搜索
const data = [
{ title: '文章1', tags: ['vue', 'javascript'] }
]
const fuse = new Fuse(data, {
keys: ['tags'] // 自動搜索數(shù)組中的每個元素
})
6.3 自定義匹配函數(shù)
const options = {
getFn: (obj, key) => {
// 自定義獲取值的邏輯
return obj[key]
}
}
6.4 擴(kuò)展搜索模式
const options = {
useExtendedSearch: true
}
const fuse = new Fuse(data, options)
// 搜索語法
fuse.search('\'exact phrase') // 精確短語
fuse.search('!exclude') // 排除
fuse.search('term1|term2') // 或
7. 性能優(yōu)化建議
7.1 大數(shù)據(jù)集優(yōu)化
// 對于大數(shù)據(jù)集,預(yù)先創(chuàng)建索引
const fuse = new Fuse(largeData, {
threshold: 0.3,
includeMatches: true
})
// 復(fù)用實例,避免重復(fù)創(chuàng)建
7.2 搜索時機(jī)控制
// 防抖搜索
let timer = null
watch(searchQuery, (newVal) => {
clearTimeout(timer)
timer = setTimeout(() => {
results.value = fuse.search(newVal)
}, 300)
})
7.3 限制返回結(jié)果
const results = fuse.search(query) const limited = results.slice(0, 10) // 只取前10條
8. 常見問題
Q1: 如何處理中文搜索?
A: Fuse.js 默認(rèn)支持中文,無需特殊配置。
Q2: 搜索速度慢怎么辦?
A:
- 減少 keys 數(shù)量
- 提高 threshold 值
- 限制數(shù)據(jù)集大小
- 使用防抖避免頻繁搜索
Q3: 如何實現(xiàn)多關(guān)鍵詞搜索?
A:
const query = 'vue javascript' const results = fuse.search(query)
Q4: 如何清除搜索結(jié)果?
A:
if (!query.trim()) return []
9. 完整參數(shù)速查表
| 參數(shù) | 類型 | 默認(rèn)值 | 說明 |
|---|---|---|---|
| keys | string[] | [] | 搜索字段 |
| threshold | number | 0.6 | 模糊度 (0-1) |
| includeScore | boolean | false | 包含分?jǐn)?shù) |
| includeMatches | boolean | false | 包含匹配信息 |
| minMatchCharLength | number | 1 | 最小匹配字符 |
| shouldSort | boolean | true | 結(jié)果排序 |
| ignoreLocation | boolean | false | 忽略位置 |
| findAllMatches | boolean | false | 查找所有匹配 |
| useExtendedSearch | boolean | false | 擴(kuò)展搜索模式 |
| location | number | 0 | 匹配位置權(quán)重 |
| distance | number | 100 | 匹配距離 |
| maxPatternLength | number | 32 | 最大模式長度 |
10. 總結(jié)
Fuse.js 是一個功能強(qiáng)大且易用的模糊搜索庫,適用于:
- ? 搜索框?qū)崟r搜索
- ? 大屏列表篩選
- ? 離線文檔搜索
- ? 系統(tǒng)菜單導(dǎo)航
- ? 知識庫檢索
通過合理配置參數(shù),可以實現(xiàn)從精確到模糊的各種搜索需求,并提供良好的用戶體驗。
相關(guān)資源
到此這篇關(guān)于Fuse.js前端模糊搜索神器從入門到精通教程的文章就介紹到這了,更多相關(guān)Fuse.js前端模糊搜索內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
移動端使用localStorage緩存Js和css文的方法(web開發(fā))
這篇文章主要介紹了web移動端使用localStorage緩存Js和css文的方法,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-09-09
echarts統(tǒng)計x軸區(qū)間的數(shù)值實例代碼詳解
這篇文章主要介紹了echarts統(tǒng)計x軸區(qū)間的數(shù)值,本文給出了實現(xiàn)實例及實例代碼,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下2019-07-07
js 將多個對象合并成一個對象 assign方法的實現(xiàn)
這篇文章主要介紹了js 將多個對象合并成一個對象 assign方法的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09

