Algolia 搜索

Algolia 是一个搜索平台,提供了一套功能和 API,使您能够轻松地为用户实现强大的搜索体验。事实上,它开箱即用地提供了工具和基础设施,可以将快速且相关的搜索功能集成到我们的应用程序中。借助 Algolia API,将其集成到您的 Qwik 应用程序中非常简单。

解决方案

要开始使用它,您需要创建一个个人 Algolia 帐户并检索您的 API 密钥,这些密钥将用于与 Algolia 交互。

  • 索引名称:索引是 Algolia 使用的数据存储位置。它相当于数据库中的表,但针对搜索和发现操作进行了优化。
  • 应用程序 ID:这是您的唯一应用程序标识符。它用于在使用 Algolia API 时识别您。
  • 仅搜索 API 密钥:这是您在前端代码中使用的公共 API 密钥。此密钥仅可用于搜索查询和将数据发送到 Insights API。

因此,一旦您拥有这些信息,您就可以通过在项目的根目录中创建或编辑 .env.env.local 文件来定义您的环境变量。

.env
VITE_ALGOLIA_INDEX=
VITE_ALGOLIA_APP_ID=
VITE_ALGOLIA_SEARCH_KEY=

您可以在下面找到第一个可用实现的工作示例。然后,您可以自定义并创建自己的图形界面。很多时候,在显示搜索和结果的模态窗口中使用搜索是有意义的,例如您在此 Qwik 文档中找到的搜索。您可以通过 官方文档 检查 Algolia 返回的内容。

import { $, component$, useSignal, useStylesScoped$ } from '@builder.io/qwik';
 
type AlgoliaResult = {
  hits: {
    type: string;
    anchor?: string;
    content?: string;
    url: string;
  }[];
};
 
export default component$(() => {
  useStylesScoped$(`
    .search {
      font-size: 100%;
      width: calc(100% - 38px);
      border-radius: 0.5rem;
      border: 1px black solid;
      padding: 1rem;
      color: black;
      outline: none;
    }
 
    .search-button {
      border: none;
      padding: 6px 0px;
      cursor: pointer;
      background-color: transparent;
      position: absolute;
      right: 2.4rem;
      padding: 0.85rem 0.5rem 0.4rem 0.5rem;
      outline: none;
    }
 
    .list {
      display: flex;
      flex-direction: column;
      align-items: center;
    }
 
    .list li {
      counter-increment: cardCount;
      display: flex;
      color: white;
      margin-top: 1rem;
      margin-bottom: 1rem;
      max-width: 500px;
    }
 
    .list li::before {
      content: counter(cardCount, decimal-leading-zero);
      background: white;
      color: var(--cardColor);
      font-size: 2em;
      font-weight: 700;
      transform: translateY(calc(-1 * 1rem));
      margin-right: calc(-1 * 1rem);
      z-index: 1;
      display: flex;
      align-items: center;
      padding-inline: 0.5em;
      border: 1px solid black;
    }
 
    .list li .content {
      background-color: var(--cardColor);
      display: grid;
      padding: 0.5em calc(1em + 1.5rem) 0.5em calc(1em + 1rem);
      grid-template-areas:
        "icon title"
        "icon text";
      gap: 0.25em;
      clip-path: polygon(
        0 0,
        calc(100% - 1.5rem) 0,
        100% 50%,
        calc(100% - 1.5rem) 100%,
        calc(100% - 1.5rem) calc(100% + 1rem),
        0 calc(100% + 1rem)
      );
    }
 
    .list li .content .title {
      grid-area: title;
      font-size: 1.25em;
    }
 
    .list li .content .text {
      grid-area: text;
      color: black;
    }
  `);
  const termSignal = useSignal('');
  const hitsSig = useSignal<AlgoliaResult['hits']>([]);
 
  const onSearch = $(async (query: string) => {
    const algoliaURL = new URL(
      `/1/indexes/${import.meta.env.VITE_ALGOLIA_INDEX}/query`,
      `https://${import.meta.env.VITE_ALGOLIA_APP_ID}-dsn.algolia.net`
    );
    const response = await fetch(algoliaURL, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-Algolia-Application-Id': import.meta.env.VITE_ALGOLIA_APP_ID!,
        'X-Algolia-API-Key': import.meta.env.VITE_ALGOLIA_SEARCH_KEY!,
      },
      body: JSON.stringify({ query }),
    });
    const algoliaResult: AlgoliaResult = await response.json();
    hitsSig.value = algoliaResult.hits;
  });
 
  return (
    <div>
      <div style="margin: 1rem;">
        <div style="position: relative;">
          <input
            class="search"
            placeholder="Algolia search: type here and press enter"
            bind:value={termSignal}
            onKeyDown$={(e) => {
              if (e.key === 'Enter') {
                onSearch(termSignal.value);
              }
            }}
          />
          <button
            type="submit"
            class="search-button"
            onClick$={() => onSearch(termSignal.value)}
          >
            <svg
              xmlns="http://www.w3.org/2000/svg"
              width="32"
              height="32"
              viewBox="0 0 24 24"
            >
              <path
                fill="currentColor"
                d="M15.5 14h-.79l-.28-.27A6.471 6.471 0 0 0 16 9.5A6.5 6.5 0 1 0 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5S14 7.01 14 9.5S11.99 14 9.5 14z"
              />
            </svg>
          </button>
        </div>
      </div>
      <div class="list">
        {hitsSig.value.map(({ anchor, content, url }, key) => (
          <li
            key={key}
            style={`--cardColor:${key % 2 === 0 ? '#19b6f6' : '#ac7ef4'}`}
          >
            <div class="content">
              <div class="title">
                {(anchor || content || url || '').substring(0, 30)}
              </div>
              <a class="text" href={url}>
                Documentation link
              </a>
            </div>
          </li>
        ))}
      </div>
    </div>
  );
});

贡献者

感谢所有帮助改进此文档的贡献者!

  • gioboa