如何在Next.js博客中集成Algolia DocSearch搜索功能

🧑‍💻
推荐全栈学习资源:
  • Next.js 中文文档:样式和官网一样的中文文档,创造沉浸式Next.js中文学习体验。
  • 《Chrome插件全栈开发》:真实出海项目的实战教学课,讲解Chrome插件和Next.js端的全栈开发,帮助你半个月内成为全栈出海工程师。
  • 最近在做「Next.js 中文文档」的自动化工作和代码升级,比较忙,所以这篇文章就长话短说,把博客/文档类网站集成搜索功能的方法介绍一下。

    差不多半年前,我发布了一个开源的博客模板,那时候我尝试使用 FlexSearch 来实现搜索。虽然开发的时候觉得很牛,但是真正去测试才发现这里有不少问题,主要是中文分词和拉丁语系不同,要想使用 FlexSearch 做出很好用的搜索效果,必须自己集成分词库,实践下来开发成本不低,那时候我只在模板里放了一个简化版的搜索,使用体验并不好。

    因为搜索功能使用频率太低了,所以我后来就没怎么研究了。直到和阿伟一起开发 Next.js 中文文档的时候,阿伟给文档站集成了 Algolia,我才重新准备修改博客模板的搜索功能,现在终于花5分钟上线了新的搜索功能。

    Algolia 有付费和免费两种,免费的是 DocSearch,只要网站的公开可访问的,都可以免费使用。

    这篇文章的目的就是介绍一下集成 DocSearch 的方法。

    申请 DocSearch

    1. 填写表单申请:https://docsearch.algolia.com/apply/
    2. 等待 Algolia 团队的邮件,等待了一天,我就收到了这样的一封邮件: email

    收到邮件表示 Algolia 已经索引好了我们的网站,现在就可以集成了。注意圈起来的参数,后面开发的搜索框组件需要使用这三个核心参数。

    代码集成步骤

    安装依赖

    pnpm i @docsearch/css @docsearch/react

    创建 config/docSearchConfig.ts 定义配置:

    /**
     * 免费申请 algolia 文档搜索功能:https://docsearch.algolia.com/apply/
     */
    interface DocSearchSiteConfig {
      docSearch: {
        appId: string;
        indexName: string;
        apiKey: string;
      };
    }
    export const docSearchConfig: DocSearchSiteConfig = {
      docSearch: {
        appId: "填写邮件收到的参数",
        indexName: "填写邮件收到的参数",
        apiKey: "填写邮件收到的参数",
      },
    }

    创建 DocSearch 搜索框组件,components/DocSearch/index.ts核心代码如下:

    "use client";
     
    import { docSearchConfig } from "@/config/docSearch";
    import "@docsearch/css";
    import { DocSearchModal, useDocSearchKeyboardEvents } from "@docsearch/react";
    import Link from "next/link";
    import { useCallback, useEffect, useRef, useState } from "react";
    import { createPortal } from "react-dom";
    import { IoIosSearch } from "react-icons/io";
    import "./docSearch.css";
     
    export default function CustomDocSearch() {
      const { appId, indexName, apiKey } = docSearchConfig.docSearch;
      const [isOpen, setIsOpen] = useState(false);
      const [isMac, setIsMac] = useState(false);
      const searchButtonRef = useRef<HTMLButtonElement>(null);
     
      const onOpen = useCallback(() => {
        setIsOpen(true);
      }, [setIsOpen]);
     
      const onClose = useCallback(() => {
        setIsOpen(false);
      }, [setIsOpen]);
     
      useDocSearchKeyboardEvents({
        isOpen,
        onOpen,
        onClose,
        searchButtonRef,
      });
     
      // 添加检测操作系统的效果
      useEffect(() => {
        setIsMac(navigator.platform.toUpperCase().indexOf("MAC") >= 0);
      }, []);
     
      return (
        <>
          <button className="docSearch-btn" data-variant="large" onClick={onOpen}>
            搜索文档<kbd>{isMac ? "⌘K" : "Ctrl+K"}</kbd>
          </button>
          <button className="docSearch-btn" data-variant="medium" onClick={onOpen}>
            搜索<kbd>{isMac ? "⌘K" : "Ctrl+K"}</kbd>
          </button>
          <button
            className="docSearch-btn mr-2 hover:bg-accent border border-gray-300"
            data-variant="small"
            onClick={onOpen}
          >
            <IoIosSearch />
          </button>
          {isOpen &&
            createPortal(
              <DocSearchModal
                initialScrollY={window.scrollY}
                appId={appId}
                apiKey={apiKey}
                indexName={indexName}
                onClose={onClose}
                placeholder="搜索文档"
                hitComponent={({ hit, children }) => (
                  <Link href={hit.url}>{children}</Link>
                )}
              />,
              document.body
            )}
        </>
      );
    }

    docSearch.css 是自定义的搜索样式。

    再把搜索框组件 CustomDocSearch 引入 Header 就可以使用了。

    总结

    DocSearch 的搜索和集成都非常方便,现在我的博客模板博客信息差周刊都已经集成好了,这三个项目都是开源的,你可以直接复制我的组件代码。

    关于我

    我是一名全栈工程师,Next.js 开源手艺人,AI降临派。

    今年致力于 Next.js 和 Node.js 领域的开源项目开发和知识分享。

    欢迎在以下平台关注我: