5分钟搞定!给Next.js项目集成React、Vue官网一样的搜索功能

721 阅读3分钟

前言

半年前,我开源了一个 Next.js 博客模板。当时为了实现站内搜索,我选择了 FlexSearch 方案。FlexSearch 是一个高性能的全文搜索库,在英文环境下表现优异。然而在实际测试中,我发现中文搜索存在严重问题。要解决这个问题,就需要引入 nodejieba 这样的中文分词库。但 nodejieba 依赖 C++ 编译环境,而我的网站都是部署在 serverless 环境,无法直接支持,所以那时候我只在模板里放了一个简化版的搜索,使用体验并不好。

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

本文首发于我的博客 J实验室

Algolia DocSearch 简介

Algolia 提供了付费的企业版和免费的 DocSearch 两种方案。DocSearch 专门针对技术文档、博客等内容网站,只要你的网站是公开可访问的,就能免费集成。

DocSearch 凭借专业的搜索能力和丝滑的用户体验,已经成为技术文档的主流搜索方案。连 React 和 Vue 这样的官方网站都在使用。

这篇教程将手把手带你在 Next.js 项目中集成 DocSearch,只需跟随以下步骤,你也能很快为网站添加专业级的站内搜索。

1、申请 DocSearch

  1. 填写表单申请:docsearch.algolia.com/apply/

  2. 等待 Algolia 团队的邮件,等待了一天,我就收到了这样的一封邮件:

    email.webp

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

2、代码集成

安装依赖

# 使用 npm
npm install @docsearch/css @docsearch/react

# 使用 yarn
yarn add @docsearch/css @docsearch/react

# 使用 pnpm
pnpm add @docsearch/css @docsearch/react

创建配置文件 config/docSearchConfig.ts

interface DocSearchConfig {
  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中文文档」体验,文档站一共有 300 多个文档,搜索效率依然非常高,所以你完全可以放心使用。

关于我

我是一名前端工程师,Next.js 手艺人,AI降临派。

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

欢迎关注我的 掘金博客 和 Github