完整教程: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.js
              const 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 text
              let highlighted = text
              const 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.item
              const 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.title
              const highlightedAuthor = authorMatch ?
              highlightMatches(book.author, [authorMatch]
              ) : book.author
              return `
              <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 集成搜索组件

找到 {{ filteredEmployees.length }} 个结果
{{ employee.item.name.charAt(0) }}
{{ employee.item.department }}
 {{ employee.item.email }} |  {{ employee.item.phone }}
匹配度: {{ Math.round((1 - employee.score) * 100) }}%
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 = results
      this.applyDepartmentFilter()
    },
    filterByDepartment(department) {
      this.selectedDepartment = department
      this.applyDepartmentFilter()
    },
    applyDepartmentFilter() {
      if (this.selectedDepartment === 'all') return
      this.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 text
        let highlighted = text
        const indices = match.indices
        for (let i = indices.length - 1; i >= 0; i--) {
          const [start, end] = indices[i]
          highlighted = highlighted.slice(0, start) +
          '' +
          highlighted.slice(start, end + 1) +
          '' +
          highlighted.slice(end + 1)
        }
        return highlighted
      }
      return text
    }
  }
}
.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;
}

案例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 text
            const match = matches[0]
            if (!match) return text
            let highlighted = text
            const indices = match.indices
            for (let i = indices.length - 1; i >= 0; i--) {
              const [start, end] = indices[i]
              highlighted = highlighted.slice(0, start) +
              '' +
              highlighted.slice(start, end + 1) +
              '' +
              highlighted.slice(end + 1)
            }
            return highlighted
          }
          return (
            ️ 产品搜索
            {/* 搜索栏 */}
             setQuery(e.target.value)}
            placeholder="搜索产品名称、品牌或分类..."
            style={{
              width: '100%',
              padding: '12px',
              fontSize: '16px',
              border: '2px solid #ddd',
              borderRadius: '8px',
              outline: 'none'
            }}
            />
            {/* 排序选项 */}
            排序:
             setSortBy(e.target.value)}
            style={{ padding: '5px 10px', borderRadius: '4px', border: '1px solid #ddd' }}
            >
            相关性
            价格从低到高
            价格从高到低
            名称
            找到 {sortedResults.length} 个结果
            {/* 搜索结果 */}
            {sortedResults.map((result) => {
              const product = result.item
              const matches = result.matches || []
              const nameMatch = matches.find(m => m.key === 'name')
              const brandMatch = matches.find(m => m.key === 'brand')
              return (
                品牌:
                {' | '}
                分类:{product.category}
                {product.tags.map(tag => (
                  {tag}
                ))}
                ¥{product.price.toLocaleString()}
                {result.score && (
                  匹配度: {Math.round((1 - result.score) * 100)}%
                )}
              )
            })}
            {sortedResults.length === 0 && query && (
              没有找到匹配的产品
            )}
          )
        }
        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 fuse
self.onmessage =
function(e
) {
const {
type, data, options, query
} = e.data
if (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 = capacity
this.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(
).value
this.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 cached
const 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 -1
if (a.score !== 0 && b.score === 0
)
return 1
// 按分数排序
return a.score - b.score
}
}

2. 动态更新索引

class DynamicFuse {
constructor(initialData, options
) {
this.options = options
this.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.exact
case 'name':
case 'title':
return thresholds.moderate
case 'description':
case 'content':
return thresholds.loose
default:
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 可以为您的应用提供专业级的搜索体验,大大提升用户满意度。


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

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

posted on 2025-06-08 16:36  ljbguanli  阅读(222)  评论(0)    收藏  举报