JavaScript >> Javascript 文檔 >  >> JavaScript

如何使用 Fuse.js 實現客戶端搜索

如何使用 Fuse.js 實現客戶端實時搜索。

對於某些應用程序,運行完整的搜索服務器並連接索引是多餘的。在其他情況下,由於需要僅離線等要求,這是不切實際的。雖然豐富的搜索體驗應該 默認情況下由運行在服務器上的真實搜索引擎驅動,在某些情況下,首選實現客戶端搜索。

開始使用

首先,對於本教程,我們將使用 CheatCode Next.js 樣板作為起點。要克隆它,請運行:

終端

git clone https://github.com/cheatcode/nextjs-boilerplate.git

接下來,cd 進入克隆項目並安裝其依賴項:

終端

cd nextjs-boilerplate && npm install

接下來,讓我們安裝 fuse.js 通過 NPM 依賴:

終端

npm i fuse.js

最後,讓我們運行一下項目:

終端

npm run dev

一旦所有這些都完成了,我們就可以開始了。

設置我們的測試數據

首先,為了連接我們的搜索,我們需要一些測試數據。我們將使用來自 Github 的國家列表。因為我們的目標是完全構建客戶端,所以我們將創建一個靜態 JavaScript 文件並將此內容放入其中:

/lib/countries.js

export default [
  { code: "AF", name: "Afghanistan" },
  [...]
  { code: "ZW", name: "Zimbabwe" },
];

接下來,我們準備開始構建我們的搜索。為了演示設置,我們將添加一個 /search 樣板中的頁面:

/pages/search/index.js

import React, { useState } from "react";

const Search = () => {
  const [searchQuery, setSearchQuery] = useState("");
  const [searchResults, setSearchResults] = useState([]);

  return (
    <div>
      // We'll build out our search and results UI here...
    </div>
  );
};

Search.propTypes = {};

export default Search;

首先,我們在這裡使用函數組件模式創建了一個骨架 React 組件。在頂部,我們用 const Search 定義我們的函數組件 .在函數體內,我們使用 useState() 在 React 中掛鉤以創建我們需要的兩個狀態值:searchQuerysearchResults .

使用 useState() 時需要注意的幾點 鉤子:

  • 當我們調用 useState() 我們傳遞給它的值代表默認值(這裡,對於 searchQuery 我們傳遞一個空字符串和 searchResults 我們傳遞一個空數組)。
  • 調用 useState() 返回一個包含兩個值的數組:當前值和用於更新值的 setter(此處為 searchQuery 是我們用於狀態值和 setSearchQuery 的名稱 允許我們更新該值)。

接下來,要創建我們的基礎組件,我們 return 一個空的 <div></div> 搜索 UI 的核心所在的標籤。

初始化我們的索引

現在,讓我們拉入我們的國家列表並使用 Fuse 創建我們的搜索索引:

/pages/search/index.js

import React, { useState } from "react";
import Fuse from "fuse.js";
import countries from "../../lib/countries";

const Search = () => {
  const [searchQuery, setSearchQuery] = useState("");
  const [searchResults, setSearchResults] = useState([]);

  const searchIndex = new Fuse(countries, {
    includeScore: true,
    threshold: 0.4,
    keys: ["name"],
  });

  return (
    <div>
      // We'll build out our search and results UI here...
    </div>
  );
};

Search.propTypes = {};

export default Search;

我們在這裡添加了一些東西。首先,在頂部,我們導入 countries.js 我們之前創建的文件。接下來,我們新建一個變量searchIndex 設置為 new Fuse() 傳遞兩件事:我們的 countries 列表 (我們要添加到索引中的數據)和一個 options 具有三個設置的對象:

  1. includeScore 告訴 Fuse 我們希望每個搜索結果都收到一個相關性分數,並且我們希望該分數返回 in 搜索結果數據。
  2. threshold 是一個數字,它決定了我們的搜索應該有多“模糊”。一個 threshold 0 意味著搜索必須與 threshold 完全匹配 1.0 表示任何東西 會匹配。 0.4 在這裡是任意的,所以請隨意使用它。
  3. keys 是描述我們要搜索的對象鍵的字符串數組。在這種情況下,我們只希望我們的搜索針對 name 我們每個國家/地區對象的屬性。

雖然看起來可能不多,但這是與 Fuse 合作的核心。很簡單,對吧?有了這個,現在我們已經準備好設置搜索 UI 並查看一些實時結果。

連接搜索 UI

首先,我們需要添加一個 <input /> 用戶可以在其中輸入搜索查詢:

/pages/search/index.js

import React, { useState } from "react";
import Fuse from "fuse.js";
import countries from "../../lib/countries";

const Search = () => {
  const [searchQuery, setSearchQuery] = useState("");
  const [searchResults, setSearchResults] = useState([]);

  const searchIndex = new Fuse(countries, {
    includeScore: true,
    threshold: 0.4,
    keys: ["name"],
  });

  const handleSearch = (searchQuery) => {
    setSearchQuery(searchQuery);
    const results = searchIndex.search(searchQuery);
    setSearchResults(results);
  };

  return (
    <div>
      <div className="mb-4">
        <input
          type="search"
          name="search"
          className="form-control"
          value={searchQuery}
          onChange={(event) => handleSearch(event.target.value)}
        />
      </div>
    </div>
  );
};

Search.propTypes = {};

export default Search;

我們在這裡添加了兩個重要的東西:首先,在 return 中 值(我們組件的標記),我們添加了一個 <input /> search 類型的標記 (這會切換瀏覽器對搜索輸入的特殊功能,例如清除按鈕)。

我們還給了它一個 className form-control 通過 Bootstrap 給它一些基本樣式(包含在我們正在使用的樣板文件中)。接下來,我們設置輸入的value 到我們的 searchQuery 狀態值,然後添加一個 onChange 處理程序,傳遞一個調用我們上面定義的另一個函數的函數,handleSearch() ,傳遞 event.target.value 表示輸入到搜索輸入中的當前值。

/pages/search/index.js

const handleSearch = (searchQuery) => {    
  setSearchQuery(searchQuery);
  const results = searchIndex.search(searchQuery);
  setSearchResults(results);
};

放大那個 handleSearch() 函數,這就是魔法發生的地方。首先,我們確保設置我們的 searchQuery (event.target.value , 傳入 handleSearch 功能為 searchQuery ) 以便我們的 UI 在用戶鍵入時更新。其次,我們執行我們的實際搜索,使用 .search() 作為 Fuse 索引實例的一部分返回的方法(我們存儲在 searchIndex 變量)。

最後,我們取results 我們從 Fuse 返回,然後將它們設置為狀態。現在,我們已經準備好渲染我們的結果並實時查看整個過程。

連接結果 UI

最後,接下來,我們需要渲染我們的搜索結果。請記住,之前作為我們傳遞給 Fuse 的選項對象的一部分,我們添加了一個 includeScore 設置,設置為 true .在我們呈現搜索結果之前,我們希望根據這個 score 創建結果的排序版本 價值。

/pages/search/index.js

import React, { useState } from "react";
import Fuse from "fuse.js";
import countries from "../../lib/countries";

const Search = () => {
  const [searchQuery, setSearchQuery] = useState("");
  const [searchResults, setSearchResults] = useState([]);
  const sortedSearchResults = searchResults.sort((resultA, resultB) => {
    return resultA.score - resultB.score;
  });

  const searchIndex = new Fuse(countries, {
    includeScore: true,
    threshold: 0.4,
    keys: ["name"],
  });

  const handleSearch = (searchQuery) => {
    setSearchQuery(searchQuery);
    const results = searchIndex.search(searchQuery);
    setSearchResults(results);
  };

  return (
    <div>
      <div className="mb-4">
        <input
          type="search"
          name="search"
          className="form-control"
          value={searchQuery}
          onChange={(event) => handleSearch(event.target.value)}
        />
      </div>
    </div>
  );
};

Search.propTypes = {};

export default Search;

在這裡,我們添加了一個 sortedSearchResults 變量就在我們的 useState() 之下 searchResults 的聲明 多變的。分配給它的是調用 searchResults.sort() 的結果 (原生 JavaScript 數組 .sort() 方法)。向它傳遞一個比較函數,它接受兩個參數:我們正在比較的當前項目 resultA (在排序中被迭代的那個)和它之後的下一個項目 resultB .

我們的比較是檢查每個分數之間的差異。 .sort() 自動 方法將使用它返回我們搜索結果數組的排序副本,按每個結果的 score 屬性。

現在我們準備好渲染結果了。讓我們添加一些樣板代碼,然後遍歷它:

/pages/search/index.js

import React, { useState } from "react";
import Fuse from "fuse.js";
import countries from "../../lib/countries";

const Search = () => {
  const [searchQuery, setSearchQuery] = useState("");
  const [searchResults, setSearchResults] = useState([]);
  const sortedSearchResults = searchResults.sort((resultA, resultB) => {
    return resultA.score - resultB.score;
  });

  const searchIndex = new Fuse(countries, {
    includeScore: true,
    threshold: 0.4,
    keys: ["name"],
  });

  const handleSearch = (searchQuery) => {
    setSearchQuery(searchQuery);
    const results = searchIndex.search(searchQuery);
    setSearchResults(results);
  };

  return (
    <div>
      <div className="mb-4">
        <input
          type="search"
          name="search"
          className="form-control"
          value={searchQuery}
          onChange={(event) => handleSearch(event.target.value)}
        />
      </div>
      {sortedSearchResults.length > 0 && (
        <ul className="list-group">
          {sortedSearchResults.map(({ item }) => {
            return (
              <li className="list-group-item" key={item.name}>
                {item.name} ({item.code})
              </li>
            );
          })}
        </ul>
      )}
    </div>
  );
};

Search.propTypes = {};

export default Search;

這樣就完成了我們的搜索 UI。在這裡,我們採用了 sortedSearchResults 我們創建並首先檢查它的長度是否大於 0 .如果它確實 ,我們要渲染我們的搜索結果 <ul></ul> .如果沒有,我們希望它隱藏。對於該列表,我們使用了 Bootstrap list-group 為我們的搜索結果加上 list-group-item 在我們每個單獨的搜索結果中分類。

對於每個搜索結果,我們只渲染 namecode (在括號中)並排。

而已!現在,如果我們在瀏覽器中加載我們的應用程序並前往 http://localhost:5000/search ,我們應該會看到我們的工作搜索 UI。

總結

在本教程中,我們學習瞭如何使用 Fuse 構建客戶端實時搜索。我們學習瞭如何在 React 中設置一個簡單的搜索組件,使用 Fuse 創建一個搜索索引(在此過程中使用數據填充它),並針對該索引執行搜索查詢。


Tutorial JavaScript 教程
  1. 從 Tailwind CSS 顏色托盤中查找最接近的顏色

  2. Devcover - 生成開發人員組合的最簡單方法

  3. 什麼是 Node,我應該什麼時候使用它?

  4. 最好的現代 JavaScript  — 參數和傳播

  5. useEffect 中的 React API 調用僅在參數被硬編碼時運行,而不是在使用狀態時運行

  6. 使用 nodejs 為 coindeal 創建機器人 - 第 1 部分

  7. 檢查字符串是否包含來自單詞數組(jquery,javascript)的整個單詞

  1. Javascript 變量賦值

  2. Immutable.JS 發生了什麼?我們該如何應對?

  3. JavaScript 中的數據結構和算法(單鍊錶)第 1 部分

  4. 如何使用 React、Material UI 和 Netlify 製作自己的(無模板)個人網站

  5. 測試 Github Codespaces beta🔥🐱‍💻

  6. 將快照中的所有 Firestore 時間戳轉換為 JS 日期的方法?

  7. Javascript window.open() 不下載文件

  1. JavaScript 中的可選鏈:簡介

  2. WordPress 的 10 個最佳 jQuery 插件

  3. Web項目界面構建的模板引擎

  4. 對可靠的網絡應用程序使用數學而不是過程