高级用法
全文搜索
使用 Nuxt Content 在你的网站中实现全文搜索。
内置 FTS5 搜索
Content 模块提供 useSearchCollection,这是一个由 SQLite FTS5 驱动的零依赖组合式函数。它会基于你的内容章节构建倒排索引,并提供带前缀匹配和摘要的即时排序搜索。
SearchExample.vue
<script setup lang="ts">
const { status, search } = useSearchCollection('docs')
const query = ref('')
const results = ref([])
watch(query, async (value) => {
results.value = value
? await search(value, { snippet: { columns: ['content'], around: 40 } })
: []
})
</script>
<template>
<UInput v-model="query" :disabled="status !== 'ready'" placeholder="搜索..." />
<ul>
<li v-for="result in results" :key="result.id">
<NuxtLink :to="result.id">{{ result.title }}</NuxtLink>
<p v-if="result.snippets?.content" v-html="result.snippets.content" />
</li>
</ul>
</template>
外部库
你也可以使用 queryCollectionSearchSections 来获取原始章节数据,并将其传递给像 Fuse.js 或 MiniSearch 这样的搜索库。这种方式可以容忍拼写错误并进行模糊匹配,但代价是需要将所有章节加载到内存中。
MiniSearch
MiniSearch 是一个轻量级的全文搜索库,支持前缀匹配、模糊搜索和字段权重提升。
<script setup lang="ts">
import MiniSearch from 'minisearch'
const query = ref('')
const { data } = await useAsyncData('search', () => queryCollectionSearchSections('docs'))
const miniSearch = new MiniSearch({
fields: ['title', 'content'],
storeFields: ['title', 'content'],
searchOptions: {
prefix: true,
fuzzy: 0.2,
},
})
// 将数据添加到 MiniSearch 实例中
miniSearch.addAll(toValue(data.value))
const result = computed(() => miniSearch.search(toValue(query)))
</script>
<template>
<UContainer class="p-4">
<UCard>
<UInput v-model="query" placeholder="搜索..." />
<ul>
<li v-for="link of result" :key="link.id" class="mt-2">
<NuxtLink :to="link.id">{{ link.title }}</NuxtLink>
<p class="text-gray-500 text-xs">{{ link.content }}</p>
</li>
</ul>
</UCard>
</UContainer>
</template>
Fuse.js
Fuse.js 是一个模糊搜索库,使用 Bitap 算法进行可容忍拼写错误的匹配,并支持可配置阈值。
<script setup lang="ts">
import Fuse from 'fuse.js'
const query = ref('')
const { data } = await useAsyncData('search-data', () => queryCollectionSearchSections('docs'))
const fuse = new Fuse(data.value, {
keys: ['title', 'description']
})
const result = computed(() => fuse.search(toValue(query)).slice(0, 10))
</script>
<template>
<UContainer class="p-4">
<UCard>
<UInput v-model="query" placeholder="搜索..." class="w-full" />
<ul>
<li v-for="link of result" :key="link.item.id" class="mt-2">
<UButton variant="ghost" class="w-full" :to="link.item.id">
{{ link.item.title }}
<span class="text-gray-500 text-xs">
{{ link.item.content?.slice(0, 100) }}...
</span>
</UButton>
</li>
</ul>
</UCard>
</UContainer>
</template>
Nuxt UI
Nuxt UI 提供了一个 ContentSearch 组件,它由 fuse.js 驱动,并可直接接收 queryCollectionSearchSections 的输出。
<script setup lang="ts">
const { data: navigation } = await useAsyncData('navigation', () => queryCollectionNavigation('docs'))
const { data: files } = await useAsyncData('search', () => queryCollectionSearchSections('docs'))
const searchTerm = ref('')
</script>
<template>
<UContentSearch
v-model:search-term="searchTerm"
:files="files"
:navigation="navigation"
:fuse="{ resultLimit: 42 }"
/>
</template>