zishu's blog

zishu's blog

一个热爱生活的博主。https://zishu.me

原生JSを使ってウェブサイトに検索機能を追加する

この記事はチュートリアルとしても考えられ、hugo ウェブサイトに検索機能を追加し、ホットリロードを実現して、より良い体験を提供します。

他のプログラムの場合、特定のテンプレートに従って以下の形式のファイルを生成するだけで済みます。主なコードは第 2 部から始まり、最初の章では hugo を使って記事リストの json ファイルを出力する方法について説明しています。

title は記事のタイトル、permalink は記事のリンクです。

[{
  "permalink": "",
  "title": ""
}, {
  "permalink": "",
  "title": ""
}]

1. hugo テンプレートで記事リストの json ファイルを生成する#

layoutsフォルダ内にindex.jsonファイルを新規作成し、テンプレート内容は以下の通りです:

2 行目の最後の "blog" はあなたの記事フォルダの名前です。大部分は posts などですが、ここは私個人の名前です。

{{- $.Scratch.Set "posts" slice -}}
{{- range where .Site.RegularPages "Type" "blog" -}}
    {{- $.Scratch.Add "posts" (dict "title" .Title "permalink" .Permalink) -}}
{{- end -}}
{{- $.Scratch.Get "posts" | jsonify -}}

このテンプレートに従って、hugo のローカルプレビューを開くと、http://localhost:1313/index.jsonで確認できます。以下のようなデータが出力された場合、成功を意味します。

image

2. js コード#

/layouts/_defaultに新しいテンプレートファイルsearch.htmlを作成し、他のテンプレートファイルを参考に大まかな構造を作成し、必要な内容を書き込みます。

まずはシンプルな html 構造を作成し、input にイベントをバインドします。

<form class="search"> 
  <input type="text" id="searchTerm" name="searchTerm" autocomplete="off" oninput="initiateSearch()">
</form>
<div id="resultsContainer">キーワードを入力して検索...</div>

次に、get リクエストを通じて json ファイルを取得し、キーワードパラメータを渡して検索リストを生成します。

<script>
  function search(jsonData, searchTerm) {
    let results = [];
    for (let i = 0; i < jsonData.length; i++) {
      for (let property in jsonData[i]) {
        if (jsonData[i].hasOwnProperty(property) && jsonData[i][property].toString().indexOf(searchTerm) > -1) {
          results.push(jsonData[i]);
          break;
        }
      }
    }
    return results;
  }

  function displayResults(searchResults) {
    let container = document.getElementById("resultsContainer");
    container.innerHTML = "";
    if (searchResults.length > 0) {
      for (let i = 0; i < searchResults.length; i++) {
        let resultDiv = document.createElement("div");
        let resultTitle = document.createElement("a");
        resultTitle.innerText = searchResults[i].title;
        resultTitle.setAttribute('href', searchResults[i].permalink)
        resultDiv.appendChild(resultTitle);
        container.appendChild(resultDiv);
      }
    } else {
      let noResultsMessage = document.createElement("p");
      noResultsMessage.innerText = "検索結果が見つかりませんでした。";
      container.appendChild(noResultsMessage);
    }
  }

  function initiateSearch() {
    let searchTerm = document.getElementById("searchTerm").value;
    let xhr = new XMLHttpRequest();
    xhr.open('GET', '/index.json', true);
    xhr.onreadystatechange = () => {
      if (xhr.readyState === 4 && xhr.status === 200) {
        let jsonData = JSON.parse(xhr.responseText);
        let searchResults = search(jsonData, searchTerm);
        displayResults(searchResults);
      }
    };
    xhr.send();
  }
</script>

次に、/contentに新しいsearch.mdファイルを作成し、このテンプレートを呼び出します。

---
slug: search
title: 検索
layout: search
---

基本的なスタイルを書きましたので、そのまま使用できます。

.search {
  width: 100%;
  display: flex;
  align-items: center;
  height: 36px;
}
.search #searchTerm {
  width: 100%;
  height: 100%;
  outline: none;
  border: none;
  padding: 0 15px;
  box-shadow: 1px 2px 10px rgba(0, 0, 0, 0.1);
}

#resultsContainer {
  margin-top: 20px;
}
#resultsContainer div {
  margin-bottom: 10px;
  margin: 0;
}
#resultsContainer div a {
  display: block;
  width: 100%;
  padding: 6px 10px;
  transition: all 0.1s linear;
  border-radius: 4px;
}
#resultsContainer div a:hover {
  background: #f3f3f3;
}
読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。