龙空技术网

使用Astro、Qwik 和 Fuse.js构建网站搜索

云云众生s 51

前言:

今天我们对“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搜索框