前言:
今天我们对“js搜索框”大体比较看重,你们都想要学习一些“js搜索框”的相关知识。那么小编同时在网摘上收集了一些有关“js搜索框””的相关文章,希望同学们能喜欢,各位老铁们一起来了解一下吧!利用 Astro 的内容集合、静态端点和 Qwik 的 Astro 集成以及 Fuse.js,构建网站搜索功能的方法。
译自 How to Build Site Search with Astro, Qwik and Fuse.js,作者 Paul Scanlon 是一名资深软件工程师、独立开发者倡导者和技术作家。更多关于 Paul 的内容可在他的网站 paulie.dev 上找到。
在这篇文章中,我将解释如何利用Astro的内容集合、静态端点以及Qwik与Fuse.js的Astro集成来构建站点搜索。
我已经准备了一个演示站点和开源仓库,你可以在以下链接找到:
内容集合是什么?
Astro提供了一种方便的方式来“批量”查询或转换相似类型的内容。在我的演示中,这将适用于所有以MDX格式编写的博客文章。所有博客文章都共享相同的模板或布局和模式。以下是博客文章的模式。
// src/content/config.jsimport { z, defineCollection } from 'astro:content';export const collections = { posts: defineCollection({ type: 'content', schema: z.object({ draft: z.boolean().optional(), audioFeedId: z.string().optional(), base: z.string(), title: z.string(), tags: z.array(z.string()).optional(), date: z.date(), author: z.string(), featuredImage: z.string(), }), }),};
你可以在这里看到存储库中的src:src/content/config.js。
为了更加保险,这里是我一篇博客文章的前置元数据(但所有博客文章将使用相同的模式)。
// src/content/posts/2024/02/the-qwik-astro-audiofeed-experiment.mdx---base: poststitle: 中 Qwik, Astro, Audiofeed 实验tags: [Qwik, Astro, Audiofeed, AI]date: 2024-02-06author: Paul ScanlonfeaturedImage: ---
你可以在存储库中查看源代码:the-qwik-astro-audiofeed-experiment.mdx。
为了构建站点搜索功能,我首先需要查询所有的博客文章。我使用了一个静态端点来实现这一点。我称之为 all-content.json.js,它位于 src/pages 目录中。例如:
// src/pages/all-content.json.jsimport { getCollection } from 'astro:content';export const GET = async () => { const posts = await getCollection('posts'); const search = posts .filter((item) => item.data.draft !== true) .map((data) => { const { slug, data: { base, title, date }, } = data; return { date: date, title: title, base: base, path: `/${base}/${slug}`, }; }) .sort((a, b) => b.date - a.date); return new Response(JSON.stringify({ search }));};
一旦我使用 getCollection('posts') 查询了所有的博客文章,我会快速过滤掉可能处于草稿模式的任何博客文章,然后仅返回对搜索有用的前置元数据字段,并按日期排序。
结果被字符串化并作为标准响应返回。
以下是结果的样式。
[ { date: 2024-02-22T00:00:00.000Z, title: '如何使用 KwesForms 和 Astro 构建调查', base: 'posts', path: '/posts/2024/02/how-to-build-a-survey-with-kwesforms-and-astro' }, { date: 2024-02-06T00:00:00.000Z, title: 'Qwik、Astro、Audiofeed 实验', base: 'posts', path: '/posts/2024/02/the-qwik-astro-audiofeed-experiment' } ...]
你可以在这里看到存储库中的源代码:src/pages/all-content.json.js。
这些数据提供了我开始构建搜索组件所需的全部信息。
如何查询静态端点
为了构建搜索组件(接下来会介绍!),我首先需要从静态端点查询数据,并将其传递给搜索组件。我在布局组件中查询数据,该组件存在于演示站点的每个页面中,例如:
// src/pages/index.astro ---import Layout from '../layouts/layout.astro';--- <Layout> <h1>Lorem ipsum</h1> <p>...</p></Layout>
你可以在这里看到存储库中的源代码:src/pages/index.astro。
以下是布局组件,它向端点发出服务器端请求。
// src/layouts/layout.astro---import Search from '../components/search';const content = await fetch(`${import.meta.env.PROD ? '; : ';}/all-content.json`);const { search } = await content.json();---<html lang='en'> <head>...</head> <body> <header> <Search data={search} /> </header> <main> <slot /> </main> </body></html>
这里需要指出的一件事是 fetch 中使用的 URL。如果站点已部署且 PROD 为 true,则静态端点的 URL 将为 ,而在开发中则使用本地主机 URL。
只要我能够查询搜索数据,我就可以通过 data 属性将其传递给我的搜索组件。
你可以在这里看到存储库中的 src:src/layouts/layout.astro。
构建搜索组件
为了构建搜索组件,需要安装两个附加依赖项。它们如下。
npm install fuse.js @qwikdev/astro
Fuse.js
我使用 Fuse.js 来帮助进行“模糊搜索”。键盘输入被捕获并传递给 Fuse.js。如果任何字母或单词与标题或日期匹配,Fuse.js 将返回该项。
Qwik
我使用 Qwik 的 Astro 集成来帮助管理客户端状态。Qwik 比 React 更轻量,并且比纯 JavaScript 更简洁。
剩下的步骤将涵盖如何设置搜索和过滤。我创建了一个简单的示例,你可以在这里预览:。源代码可以在这里找到:src/components/simple-search.jsx。
注意:我的演示中使用的示例包含大量额外的 CSS 和 JavaScript 来处理模态框,这并不是创建搜索功能所必需的。
搜索组件:第一步
第一步是创建搜索组件并返回一个 HTML 输入框。添加一个 onInput$ 事件处理程序,并创建一个名为 handleInput 的函数来捕获按键。
// src/components/simple-search.jsximport { component$, $ } from '@builder.io/qwik';const Search = component$(({ data }) => { const handleInput = $(async (event) => { const { target: { value }, } = event; }); return ( <div> <input type='text' placeholder='搜索' onInput$={handleInput} /> </div> );});export default Search;搜索组件:第二步
接下来,导入 useSignal,并创建两个新的常量来保存所有数据和过滤后的数据。
// src/components/simple-search.jsx- import { component$, $ } from '@builder.io/qwik';+ import { component$, $, useSignal } from '@builder.io/qwik';const Search = component$(({ data }) => {+ const all = useSignal(data);+ const filtered = useSignal(data); const handleInput = $(async (event) => { const { target: { value }, } = event; }); return ( <div> <input type='text' placeholder='搜索' onInput$={handleInput} /> </div> );});export default Search;搜索组件:第三步
接下来,导入并初始化 Fuse.js。Fuse.js 的配置接受来自 useSignal 常量(all.value)的值,并在任何输入值与标题或日期的值匹配时应用模糊过滤阈值为 0.5。
fuse.search 可用于过滤数组中不符合配置参数的任何项,并返回一个新数组。我将这个新数组称为“results”。
// src/components/simple-search.jsximport { component$, $, useSignal } from '@builder.io/qwik';const Search = component$(({ data }) => { const all = useSignal(data); const filtered = useSignal(data); const handleInput = $(async (event) => { const { target: { value }, } = event; const FuseModule = await import('fuse.js'); const Fuse = FuseModule.default; const fuse = new Fuse(all.value, { threshold: 0.5, keys: ['title', 'date'], }); const results = fuse.search(value).map((data) => { const { item: { base, path, title, date } } = data; return { title, date, path, base, }; }); if (value) { filtered.value = results; } else { filtered.value = all.value; } }); return ( <div> <input type='text' placeholder='搜索' onInput$={handleInput} /> </div> );});export default Search;搜索组件:第四步
接下来是添加一个 if 语句。如果从 HTML 输入中捕获到值,那么我将 useSignal filtered.value 设置为结果,如果未从 HTML 输入中捕获到值,那么我将 useSignal filtered.value 设置为 all.value。
这将返回一个过滤后的列表,或者整个列表。
// src/components/simple.search.jsximport { component$, $, useSignal } from '@builder.io/qwik';const Search = component$(({ data }) => { const all = useSignal(data); const filtered = useSignal(data); const handleInput = $(async (event) => { ... if (value) { filtered.value = results; } else { filtered.value = all.value; } }); return ( <div> <input type='text' placeholder='搜索' onInput$={handleInput} /> </div> );});export default Search;搜索组件:第五步
最后一步是遍历 filtered.value(如果有长度)并返回项目列表。如果没有结果,则返回 null。
// src/components/simple-search.jsximport { component$, $, useSignal } from '@builder.io/qwik';const Search = component$(({ data }) => { const all = useSignal(data); const filtered = useSignal(data); const handleInput = $(async (event) => { ... }); return ( <div> <input type='text' placeholder='搜索' onInput$={handleInput} /> <ul> {filtered.value.length > 0 ? filtered.value.map((data, index) => { const { path, title } = data; return ( <li key={index}> <a href={path}>{title}</a> </li> ); }) : null} </ul> </div> );});export default Search;完成
至此,我们已经掌握了如何使用 Astro 的内容集合查询数据的原理,如何通过静态端点使数据可用,以及如何使用 Fuse.js 和 Qwik 的 Astro 集成来实现模糊搜索并管理客户端状态。
我在我的网站上也采用了同样的方法,目前效果还不错!
标签: #js搜索框