当前位置: 首页 > news >正文

Fuse.js:打造极致模糊搜索体验

Fuse.js 完全学习指南:JavaScript模糊搜索库

🎯 什么是 Fuse.js?

Fuse.js 是一个轻量、强大且无依赖的JavaScript模糊搜索库。它提供了简单而强大的模糊搜索功能,可以在任何 JavaScript 环境中使用,包括浏览器和 Node.js。

🌟 核心特点

  • 轻量级:压缩后仅 ~12KB,无外部依赖
  • 模糊搜索:支持拼写错误、部分匹配等容错搜索
  • 高度可配置:提供丰富的配置选项控制搜索行为
  • 多字段搜索:支持在对象的多个字段中搜索
  • 权重系统:不同字段可以设置不同的搜索权重
  • 高亮显示:支持搜索结果高亮显示
  • 跨平台:支持浏览器、Node.js、Deno等环境
  • TypeScript支持:提供完整的TypeScript类型定义

📦 安装与引入

NPM 安装

# 使用 npm
npm install fuse.js# 使用 yarn
yarn add fuse.js

引入方式

ES6 模块语法
import Fuse from 'fuse.js'
CommonJS
const Fuse = require('fuse.js')
直接 <script> 引入
<!-- 开发版本 -->
<script src="https://cdn.jsdelivr.net/npm/fuse.js/dist/fuse.js"></script><!-- 生产版本(推荐) -->
<script src="https://cdn.jsdelivr.net/npm/fuse.js@7.1.0/dist/fuse.min.js"></script><!-- ES 模块版本 -->
<script type="module">import Fuse from 'https://cdn.jsdelivr.net/npm/fuse.js@7.1.0/dist/fuse.mjs'
</script>
Deno
// @deno-types="https://deno.land/x/fuse@v7.1.0/dist/fuse.d.ts"
import Fuse from 'https://deno.land/x/fuse@v7.1.0/dist/fuse.min.mjs'

🚀 基础使用

1. 简单数组搜索

// 创建简单的字符串数组
const books = ["老人与海","百年孤独", "哈利·波特","三体","1984","了不起的盖茨比"
]// 创建 Fuse 实例
const fuse = new Fuse(books)// 执行搜索
const result = fuse.search('盖茨比')
console.log(result)
/*
输出:
[{item: "了不起的盖茨比",refIndex: 5}
]
*/

2. 对象数组搜索

// 创建对象数组
const books = [{title: "老人与海",author: "海明威",year: 1952,genre: "小说"},{title: "百年孤独",author: "马尔克斯", year: 1967,genre: "魔幻现实主义"},{title: "三体",author: "刘慈欣",year: 2006,genre: "科幻"}
]// 指定搜索字段
const options = {keys: ['title', 'author']
}const fuse = new Fuse(books, options)// 搜索示例
const result = fuse.search('刘慈')
console.log(result)
/*
输出:
[{item: {title: "三体",author: "刘慈欣",year: 2006,genre: "科幻"},refIndex: 2}
]
*/

⚙️ 配置选项详解

基础搜索配置

const options = {// 是否按分数排序结果shouldSort: true,// 包含匹配结果的元数据includeMatches: true,// 包含分数信息includeScore: true,// 分数阈值(0.0 = 完全匹配,1.0 = 匹配任何内容)threshold: 0.3,// 搜索位置location: 0,// 搜索距离distance: 100,// 最小匹配字符长度minMatchCharLength: 1,// 是否查找所有匹配findAllMatches: false
}

搜索字段配置

const options = {keys: [// 简单字段'title','author',// 带权重的字段(权重范围 0-1){name: 'title',weight: 0.8  // 标题权重更高},{name: 'author', weight: 0.2  // 作者权重较低},// 嵌套字段'author.firstName','author.lastName',// 带权重的嵌套字段{name: 'tags',weight: 0.5}]
}

高级配置选项

const options = {// 忽略大小写isCaseSensitive: false,// 忽略变音符号ignoreLocation: false,// 忽略字段长度规范ignoreFieldNorm: false,// 字段长度规范影响因子fieldNormWeight: 1,// 搜索算法选择useExtendedSearch: false
}

🔍 搜索功能详解

1. 基础模糊搜索

const books = [{ title: "JavaScript高级程序设计" },{ title: "Vue.js实战" },{ title: "React技术栈开发" },{ title: "Node.js权威指南" }
]const fuse = new Fuse(books, {keys: ['title'],threshold: 0.4
})// 模糊搜索(允许拼写错误)
console.log(fuse.search('javscript'))  // 找到 "JavaScript高级程序设计"
console.log(fuse.search('vue'))        // 找到 "Vue.js实战"
console.log(fuse.search('react'))      // 找到 "React技术栈开发"

2. 扩展搜索语法

const options = {keys: ['title', 'author'],useExtendedSearch: true
}const fuse = new Fuse(books, options)// 精确匹配
console.log(fuse.search('="Node.js"'))// 包含搜索
console.log(fuse.search("'js"))// 排除搜索
console.log(fuse.search('!vue'))// 前缀搜索
console.log(fuse.search('^java'))// 后缀搜索
console.log(fuse.search('.js$'))// 逻辑运算符
console.log(fuse.search('javascript | vue'))  // OR
console.log(fuse.search('node !express'))     // AND NOT

3. 获取搜索匹配详情

const options = {keys: ['title'],includeMatches: true,includeScore: true,threshold: 0.3
}const fuse = new Fuse(books, options)
const result = fuse.search('javascript')console.log(result)
/*
输出:
[{item: { title: "JavaScript高级程序设计" },refIndex: 0,score: 0.001,matches: [{indices: [[0, 9]],value: "JavaScript高级程序设计",key: "title"}]}
]
*/

🎨 实际应用案例

案例1:书籍搜索系统

<!DOCTYPE html>
<html lang="zh">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>图书搜索系统</title><script src="https://cdn.jsdelivr.net/npm/fuse.js@7.1.0/dist/fuse.min.js"></script><style>.search-container {max-width: 800px;margin: 50px auto;padding: 20px;}.search-box {width: 100%;padding: 12px;font-size: 16px;border: 2px solid #ddd;border-radius: 8px;margin-bottom: 20px;}.book-item {border: 1px solid #eee;border-radius: 8px;padding: 15px;margin-bottom: 10px;background: white;box-shadow: 0 2px 4px rgba(0,0,0,0.1);}.book-title {font-size: 18px;font-weight: bold;color: #333;margin-bottom: 5px;}.book-meta {color: #666;font-size: 14px;}.highlight {background-color: yellow;font-weight: bold;}.no-results {text-align: center;color: #999;padding: 50px;}</style>
</head>
<body><div class="search-container"><h1>📚 图书搜索系统</h1><input type="text" class="search-box" placeholder="搜索书名、作者或分类..." id="searchInput"><div id="results"></div></div><script>// 书籍数据const books = [{title: "JavaScript高级程序设计",author: "Nicholas C. Zakas",year: 2020,category: "编程",rating: 4.8,description: "JavaScript开发者必读经典,深入解析语言特性"},{title: "Vue.js实战",author: "梁灏",year: 2019,category: "前端",rating: 4.6,description: "Vue.js框架实战指南,从入门到精通"},{title: "三体",author: "刘慈欣",year: 2006,category: "科幻",rating: 4.9,description: "获得雨果奖的中国科幻小说代表作"},{title: "百年孤独",author: "加西亚·马尔克斯",year: 1967,category: "文学",rating: 4.7,description: "魔幻现实主义文学的巅峰之作"},{title: "设计模式",author: "Gang of Four",year: 1994,category: "编程",rating: 4.5,description: "软件工程中的设计模式经典教材"}]// 配置 Fuse.jsconst options = {keys: [{ name: 'title', weight: 0.4 },{ name: 'author', weight: 0.3 },{ name: 'category', weight: 0.2 },{ name: 'description', weight: 0.1 }],threshold: 0.3,includeMatches: true,includeScore: true}const fuse = new Fuse(books, options)// 高亮显示匹配文本function highlightMatches(text, matches) {if (!matches || matches.length === 0) return textlet highlighted = textconst indices = matches[0].indices// 从后往前替换,避免索引偏移for (let i = indices.length - 1; i >= 0; i--) {const [start, end] = indices[i]highlighted = highlighted.slice(0, start) + '<span class="highlight">' + highlighted.slice(start, end + 1) + '</span>' + highlighted.slice(end + 1)}return highlighted}// 渲染搜索结果function renderResults(results) {const resultsContainer = document.getElementById('results')if (results.length === 0) {resultsContainer.innerHTML = '<div class="no-results">没有找到相关书籍</div>'return}const html = results.map(result => {const book = result.itemconst matches = result.matches || []// 获取标题和作者的匹配高亮const titleMatch = matches.find(m => m.key === 'title')const authorMatch = matches.find(m => m.key === 'author')const highlightedTitle = titleMatch ? highlightMatches(book.title, [titleMatch]) : book.titleconst highlightedAuthor = authorMatch ? highlightMatches(book.author, [authorMatch]) : book.authorreturn `<div class="book-item"><div class="book-title">${highlightedTitle}</div><div class="book-meta">作者:${highlightedAuthor} | 年份:${book.year} | 分类:${book.category} | 评分:${book.rating}⭐</div><div style="margin-top: 8px; color: #666; font-size: 14px;">${book.description}</div></div>`}).join('')resultsContainer.innerHTML = html}// 搜索处理function handleSearch() {const query = document.getElementById('searchInput').value.trim()if (query === '') {renderResults(books.map((book, index) => ({ item: book, refIndex: index })))return}const results = fuse.search(query)renderResults(results)}// 绑定事件document.getElementById('searchInput').addEventListener('input', handleSearch)// 初始显示所有书籍renderResults(books.map((book, index) => ({ item: book, refIndex: index })))</script>
</body>
</html>

案例2:Vue.js 集成搜索组件

<template><div class="search-component"><div class="search-header"><inputv-model="searchQuery"@input="handleSearch"class="search-input"placeholder="搜索员工姓名、部门或技能..."autocomplete="off"><div class="search-stats" v-if="searchQuery">找到 {{ filteredEmployees.length }} 个结果</div></div><div class="filters"><button v-for="dept in departments" :key="dept"@click="filterByDepartment(dept)":class="['filter-btn', { active: selectedDepartment === dept }]">{{ dept }}</button></div><div class="results-container"><div v-for="employee in filteredEmployees" :key="employee.item.id"class="employee-card"><div class="employee-avatar">{{ employee.item.name.charAt(0) }}</div><div class="employee-info"><h3 v-html="highlightText(employee.item.name, employee.matches, 'name')"></h3><p class="department">{{ employee.item.department }}</p><div class="skills"><span v-for="skill in employee.item.skills" :key="skill"class="skill-tag"v-html="highlightText(skill, employee.matches, 'skills')"></span></div><div class="contact">📧 {{ employee.item.email }} | 📞 {{ employee.item.phone }}</div></div><div class="score" v-if="employee.score">匹配度: {{ Math.round((1 - employee.score) * 100) }}%</div></div></div></div>
</template><script>
import Fuse from 'fuse.js'export default {name: 'EmployeeSearch',data() {return {searchQuery: '',selectedDepartment: 'all',employees: [{id: 1,name: '张三',department: '技术部',email: 'zhangsan@company.com',phone: '138****1234',skills: ['JavaScript', 'Vue.js', 'Node.js', 'Python']},{id: 2,name: '李四',department: '设计部',email: 'lisi@company.com',phone: '139****5678',skills: ['Photoshop', 'Figma', 'UI设计', '用户体验']},{id: 3,name: '王五',department: '产品部',email: 'wangwu@company.com',phone: '137****9012',skills: ['产品规划', '数据分析', 'Axure', 'SQL']},{id: 4,name: '赵六',department: '技术部',email: 'zhaoliu@company.com',phone: '136****3456',skills: ['React', 'TypeScript', 'GraphQL', 'MongoDB']}],filteredEmployees: [],fuse: null}},computed: {departments() {const depts = ['all', ...new Set(this.employees.map(emp => emp.department))]return depts}},mounted() {this.initializeFuse()this.filteredEmployees = this.employees.map((emp, index) => ({item: emp,refIndex: index}))},methods: {initializeFuse() {const options = {keys: [{ name: 'name', weight: 0.4 },{ name: 'department', weight: 0.2 },{ name: 'skills', weight: 0.3 },{ name: 'email', weight: 0.1 }],threshold: 0.3,includeMatches: true,includeScore: true,minMatchCharLength: 1}this.fuse = new Fuse(this.employees, options)},handleSearch() {if (!this.searchQuery.trim()) {this.filteredEmployees = this.employees.map((emp, index) => ({item: emp,refIndex: index}))this.applyDepartmentFilter()return}const results = this.fuse.search(this.searchQuery)this.filteredEmployees = resultsthis.applyDepartmentFilter()},filterByDepartment(department) {this.selectedDepartment = departmentthis.applyDepartmentFilter()},applyDepartmentFilter() {if (this.selectedDepartment === 'all') returnthis.filteredEmployees = this.filteredEmployees.filter(emp => emp.item.department === this.selectedDepartment)},highlightText(text, matches, key) {if (!matches || !Array.isArray(text)) {const match = matches?.find(m => m.key === key)if (!match) return textlet highlighted = textconst indices = match.indicesfor (let i = indices.length - 1; i >= 0; i--) {const [start, end] = indices[i]highlighted = highlighted.slice(0, start) + '<mark>' + highlighted.slice(start, end + 1) + '</mark>' + highlighted.slice(end + 1)}return highlighted}return text}}
}
</script><style scoped>
.search-component {max-width: 1000px;margin: 0 auto;padding: 20px;
}.search-header {margin-bottom: 20px;
}.search-input {width: 100%;padding: 12px 16px;font-size: 16px;border: 2px solid #e1e5e9;border-radius: 8px;outline: none;transition: border-color 0.3s;
}.search-input:focus {border-color: #007bff;
}.search-stats {margin-top: 8px;color: #666;font-size: 14px;
}.filters {display: flex;gap: 10px;margin-bottom: 20px;
}.filter-btn {padding: 8px 16px;border: 1px solid #ddd;background: white;border-radius: 20px;cursor: pointer;transition: all 0.3s;
}.filter-btn:hover,
.filter-btn.active {background: #007bff;color: white;border-color: #007bff;
}.results-container {display: grid;gap: 15px;
}.employee-card {display: flex;align-items: center;padding: 20px;border: 1px solid #e1e5e9;border-radius: 8px;background: white;transition: box-shadow 0.3s;
}.employee-card:hover {box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}.employee-avatar {width: 50px;height: 50px;border-radius: 50%;background: #007bff;color: white;display: flex;align-items: center;justify-content: center;font-size: 18px;font-weight: bold;margin-right: 15px;
}.employee-info {flex: 1;
}.employee-info h3 {margin: 0 0 5px 0;font-size: 18px;
}.department {color: #666;margin: 0 0 10px 0;
}.skills {display: flex;flex-wrap: wrap;gap: 5px;margin-bottom: 10px;
}.skill-tag {background: #f8f9fa;padding: 4px 8px;border-radius: 12px;font-size: 12px;color: #495057;
}.contact {font-size: 14px;color: #666;
}.score {text-align: right;color: #28a745;font-weight: bold;
}/* 高亮样式 */
:deep(mark) {background-color: #ffeb3b;color: #333;padding: 1px 2px;border-radius: 2px;
}
</style>

案例3:React Hooks 集成

import React, { useState, useMemo, useCallback } from 'react'
import Fuse from 'fuse.js'// 自定义 Hook:useFuseSearch
function useFuseSearch(data, options) {const [query, setQuery] = useState('')const fuse = useMemo(() => {return new Fuse(data, options)}, [data, options])const results = useMemo(() => {if (!query.trim()) {return data.map((item, index) => ({ item, refIndex: index }))}return fuse.search(query)}, [fuse, query, data])return {query,setQuery,results,search: useCallback((searchQuery) => {return fuse.search(searchQuery)}, [fuse])}
}// 主搜索组件
function ProductSearch() {const products = [{id: 1,name: 'MacBook Pro 16寸',brand: 'Apple',category: '笔记本电脑',price: 16999,tags: ['高性能', '创作', '专业']},{id: 2,name: 'iPhone 14 Pro',brand: 'Apple', category: '智能手机',price: 7999,tags: ['摄影', '5G', '高端']},{id: 3,name: 'Surface Laptop 5',brand: 'Microsoft',category: '笔记本电脑',price: 8888,tags: ['轻薄', '办公', '便携']},{id: 4,name: 'Galaxy S23 Ultra',brand: 'Samsung',category: '智能手机',price: 9999,tags: ['大屏', 'S Pen', '摄影']}]const searchOptions = {keys: [{ name: 'name', weight: 0.4 },{ name: 'brand', weight: 0.3 },{ name: 'category', weight: 0.2 },{ name: 'tags', weight: 0.1 }],threshold: 0.3,includeMatches: true,includeScore: true}const { query, setQuery, results } = useFuseSearch(products, searchOptions)const [sortBy, setSortBy] = useState('relevance')// 排序结果const sortedResults = useMemo(() => {const sorted = [...results]switch (sortBy) {case 'price-asc':return sorted.sort((a, b) => a.item.price - b.item.price)case 'price-desc':return sorted.sort((a, b) => b.item.price - a.item.price)case 'name':return sorted.sort((a, b) => a.item.name.localeCompare(b.item.name))default:return sorted // 保持相关性排序}}, [results, sortBy])// 高亮匹配文本const highlightMatches = (text, matches) => {if (!matches || matches.length === 0) return textconst match = matches[0]if (!match) return textlet highlighted = textconst indices = match.indicesfor (let i = indices.length - 1; i >= 0; i--) {const [start, end] = indices[i]highlighted = highlighted.slice(0, start) + '<mark style="background: #ffeb3b; padding: 1px 2px; border-radius: 2px;">' + highlighted.slice(start, end + 1) + '</mark>' + highlighted.slice(end + 1)}return highlighted}return (<div style={{ maxWidth: '800px', margin: '50px auto', padding: '20px' }}><h1>🛍️ 产品搜索</h1>{/* 搜索栏 */}<div style={{ marginBottom: '20px' }}><inputtype="text"value={query}onChange={(e) => setQuery(e.target.value)}placeholder="搜索产品名称、品牌或分类..."style={{width: '100%',padding: '12px',fontSize: '16px',border: '2px solid #ddd',borderRadius: '8px',outline: 'none'}}/></div>{/* 排序选项 */}<div style={{ marginBottom: '20px', display: 'flex', gap: '10px', alignItems: 'center' }}><span>排序:</span><select value={sortBy} onChange={(e) => setSortBy(e.target.value)}style={{ padding: '5px 10px', borderRadius: '4px', border: '1px solid #ddd' }}><option value="relevance">相关性</option><option value="price-asc">价格从低到高</option><option value="price-desc">价格从高到低</option><option value="name">名称</option></select><span style={{ marginLeft: 'auto', color: '#666' }}>找到 {sortedResults.length} 个结果</span></div>{/* 搜索结果 */}<div style={{ display: 'grid', gap: '15px' }}>{sortedResults.map((result) => {const product = result.itemconst matches = result.matches || []const nameMatch = matches.find(m => m.key === 'name')const brandMatch = matches.find(m => m.key === 'brand')return (<divkey={product.id}style={{border: '1px solid #eee',borderRadius: '8px',padding: '20px',background: 'white',boxShadow: '0 2px 4px rgba(0,0,0,0.1)'}}><div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'start' }}><div style={{ flex: 1 }}><h3 style={{ margin: '0 0 5px 0', fontSize: '18px' }}dangerouslySetInnerHTML={{__html: nameMatch ? highlightMatches(product.name, [nameMatch]) : product.name}}/><p style={{ margin: '0 0 10px 0', color: '#666' }}>品牌:<span dangerouslySetInnerHTML={{__html: brandMatch ? highlightMatches(product.brand, [brandMatch]) : product.brand}} />{' | '}分类:{product.category}</p><div style={{ display: 'flex', gap: '5px', marginBottom: '10px' }}>{product.tags.map(tag => (<spankey={tag}style={{background: '#f0f0f0',padding: '2px 8px',borderRadius: '12px',fontSize: '12px',color: '#666'}}>{tag}</span>))}</div></div><div style={{ textAlign: 'right' }}><div style={{ fontSize: '20px', fontWeight: 'bold', color: '#e74c3c' }}>¥{product.price.toLocaleString()}</div>{result.score && (<div style={{ fontSize: '12px', color: '#999', marginTop: '5px' }}>匹配度: {Math.round((1 - result.score) * 100)}%</div>)}</div></div></div>)})}</div>{sortedResults.length === 0 && query && (<div style={{ textAlign: 'center', padding: '50px', color: '#999' }}>没有找到匹配的产品</div>)}</div>)
}export default ProductSearch

🔧 性能优化建议

1. 大数据集处理

// 对于大数据集,考虑使用 Web Workers
class FuseWorker {constructor(data, options) {this.worker = new Worker('/fuse-worker.js')this.worker.postMessage({ type: 'init', data, options })}search(query) {return new Promise((resolve) => {this.worker.onmessage = (e) => {if (e.data.type === 'search-result') {resolve(e.data.results)}}this.worker.postMessage({ type: 'search', query })})}
}// fuse-worker.js
let fuseself.onmessage = function(e) {const { type, data, options, query } = e.dataif (type === 'init') {importScripts('https://cdn.jsdelivr.net/npm/fuse.js@7.1.0/dist/fuse.min.js')fuse = new Fuse(data, options)}if (type === 'search' && fuse) {const results = fuse.search(query)self.postMessage({ type: 'search-result', results })}
}

2. 防抖搜索

// 使用防抖避免频繁搜索
function useDebounce(value, delay) {const [debouncedValue, setDebouncedValue] = useState(value)useEffect(() => {const handler = setTimeout(() => {setDebouncedValue(value)}, delay)return () => {clearTimeout(handler)}}, [value, delay])return debouncedValue
}// 在组件中使用
function SearchComponent() {const [query, setQuery] = useState('')const debouncedQuery = useDebounce(query, 300)const results = useMemo(() => {if (!debouncedQuery) return []return fuse.search(debouncedQuery)}, [debouncedQuery])// ...
}

3. 结果缓存

// 简单的 LRU 缓存实现
class LRUCache {constructor(capacity) {this.capacity = capacitythis.cache = new Map()}get(key) {if (this.cache.has(key)) {const value = this.cache.get(key)this.cache.delete(key)this.cache.set(key, value)return value}return null}set(key, value) {if (this.cache.has(key)) {this.cache.delete(key)} else if (this.cache.size >= this.capacity) {const firstKey = this.cache.keys().next().valuethis.cache.delete(firstKey)}this.cache.set(key, value)}
}// 带缓存的搜索函数
const searchCache = new LRUCache(100)function cachedSearch(fuse, query) {const cached = searchCache.get(query)if (cached) return cachedconst results = fuse.search(query)searchCache.set(query, results)return results
}

🛠️ 高级功能

1. 自定义评分函数

const options = {// 自定义字段权重getFn: (obj, path) => {// 自定义字段获取逻辑if (path === 'fullName') {return `${obj.firstName} ${obj.lastName}`}return obj[path]},// 自定义排序函数sortFn: (a, b) => {// 优先显示完全匹配if (a.score === 0 && b.score !== 0) return -1if (a.score !== 0 && b.score === 0) return 1// 按分数排序return a.score - b.score}
}

2. 动态更新索引

class DynamicFuse {constructor(initialData, options) {this.options = optionsthis.data = [...initialData]this.fuse = new Fuse(this.data, options)}add(item) {this.data.push(item)this.rebuildIndex()}remove(predicate) {this.data = this.data.filter(item => !predicate(item))this.rebuildIndex()}update(predicate, updater) {this.data = this.data.map(item => predicate(item) ? updater(item) : item)this.rebuildIndex()}rebuildIndex() {this.fuse = new Fuse(this.data, this.options)}search(query) {return this.fuse.search(query)}
}

3. 多语言支持

// 多语言搜索配置
const multiLanguageOptions = {keys: ['title.zh','title.en', 'description.zh','description.en'],threshold: 0.3,// 自定义获取函数支持多语言getFn: (obj, path) => {const locale = getCurrentLocale() // 获取当前语言if (path.includes('.')) {const [field, lang] = path.split('.')return obj[field] && obj[field][lang]}return obj[path]}
}// 多语言数据示例
const multiLanguageData = [{id: 1,title: {zh: '苹果手机',en: 'Apple iPhone'},description: {zh: '高端智能手机',en: 'Premium smartphone'}}
]

📝 最佳实践

1. 合理设置阈值

// 不同场景的阈值建议
const thresholds = {exact: 0.0,        // 精确匹配strict: 0.2,       // 严格搜索moderate: 0.4,     // 中等容错loose: 0.6,        // 宽松搜索veryLoose: 0.8     // 非常宽松
}// 根据数据类型选择合适的阈值
const getThreshold = (dataType) => {switch (dataType) {case 'email':case 'id':return thresholds.exactcase 'name':case 'title':return thresholds.moderatecase 'description':case 'content':return thresholds.loosedefault:return thresholds.moderate}
}

2. 优化搜索键配置

// 智能权重分配
const getSearchKeys = (dataFields) => {return dataFields.map(field => {let weight = 0.1 // 默认权重// 根据字段类型分配权重if (field.includes('title') || field.includes('name')) {weight = 0.4} else if (field.includes('tag') || field.includes('category')) {weight = 0.3} else if (field.includes('description') || field.includes('content')) {weight = 0.2}return { name: field, weight }})
}

3. 错误处理

class SafeFuse {constructor(data, options) {try {this.fuse = new Fuse(data, options)this.isReady = true} catch (error) {console.error('Fuse.js 初始化失败:', error)this.isReady = false}}search(query) {if (!this.isReady) {console.warn('Fuse.js 未就绪,返回原始数据')return []}try {return this.fuse.search(query)} catch (error) {console.error('搜索出错:', error)return []}}
}

🎯 总结

Fuse.js 是一个功能强大且易用的模糊搜索库,适用于各种 JavaScript 应用场景:

简单易用:API设计简洁,上手快速
功能丰富:支持模糊搜索、权重配置、高亮显示等
高度可配置:提供30+个配置选项满足不同需求
性能优秀:轻量级设计,适合大数据集处理
跨平台支持:浏览器、Node.js、Deno 全平台兼容
TypeScript友好:完整的类型定义支持

通过合理配置和优化,Fuse.js 可以为您的应用提供专业级的搜索体验,大大提升用户满意度。


开始您的智能搜索之旅吧! 🔍

💡 开发建议:在实际项目中,建议结合防抖、缓存、虚拟滚动等技术,构建高性能的搜索系统。

相关文章:

  • 基于Java的OPCDA采集中间件
  • Java密码加密存储算法,SpringBoot 实现密码安全存储
  • 蓝桥杯_DS18B20温度传感器---新手入门级别超级详细解析
  • PACS系统全景图:软件源码、核心组件、覆盖科室与关键技术解析
  • 进程——环境变量及程序地址空间
  • 虚拟线程与消息队列:Spring Boot 3.5 中异步架构的演进与选择
  • 区块链技术赋能供应链金融:重塑信任与效率
  • Oracle中的循环——FOR循环、WHILE循环和LOOP循环
  • MySQL 如何判断某个表中是否存在某个字段
  • OpenCV 滑动条调整图像亮度
  • 使用 C++/OpenCV 图像直方图比较两个图片相似度
  • C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。
  • JsonCpp 库如何集成到Visual studio
  • iOS 应用如何防止源码与资源被轻易还原?多维度混淆策略与实战工具盘点(含 Ipa Guard)
  • 3. 简述node.js特性与底层原理
  • Vue3 + Vite:我的 Qiankun 微前端主子应用实践指南
  • 每日算法 -【Swift 算法】查找字符串数组中的最长公共前缀
  • 练习:对象数组 3
  • 【AI学习从零至壹】基于深度学习的⽂本分类任务
  • Delphi SetFileSecurity 设置安全描述符
  • 自己写的网站怎么发布/百度搜索榜排名
  • 全国建设地产网站/seo优化包括哪些
  • 金州新区规划建设局网站/网站服务器ip查询
  • 外贸推广信邮件/网站seo基础优化
  • 做论坛网站需要多少钱/广州网络公司
  • 铜仁网站建设公司/2023免费网站推广大全