お茶漬けぶろぐ

検索バーをつけたよ

ブログというのをどうして書いてるのかというと、過去やったことを記録しておきたいからなのだが、後で見返したいというのが一番大きい。
Wordpressを使っていた頃はテンプレートについていた検索機能をそのまま使っていたから、何も苦労はなかったのだけど、これからは必要な機能は自前で用意しないといけないのだ…というわけで作った話。

実際には検索してヒットしたものを使わせてもらったのだが、まぁ自分でどうしたのかというところも含めて、記録しておく。

参考:Jekyll製ウェブサイトに簡易検索機能を実装する
— Genji App Blog

記事の情報を持つjsonファイルを用意する

まずはjsonを出力するようなレイアウトを作成する。

$ cat _layouts/posts.json
[
  {% if page.target == "home" %}
    {%- assign posts = site.posts -%}
  {% else %}
    {%- assign posts = site.posts | where_exp:"item", "item.categories contains page.target" -%}
  {% endif %}
  {%- for subPost in posts -%}
  {
      "title": "{{ subPost.title | xml_escape }}",
      "description": "{{ subPost.description | xml_escape }}",
      "text": {{ subPost.content | jsonify }},
      "url": "{{ site.url }}/{{subPost.lang}}{{ subPost.url }}",
      "date": "{{ subPost.last_modified_at | date_to_xmlschema }}",
      "category": "{{ subPost.categories }}"
  }
  {%- unless forloop.last -%},{%- endunless -%}
  {%- endfor -%}
]

実際にjsonファイルを作ってもらえるようにpostを作成する。

$ cat _posts/2000-01-01-posts.md
---
layout: 'posts'
permalink: '/api/posts.json'
target: 'home'
---

実際にアクセスして、それっぽいjsonファイルが取得できることを確認しておく。

検索バーの作成

検索キーワードの入力を受ける箱、検索結果を表示する場所を作成する。

$ cat _includes/search_bar.html
<div class="container">
  <div id="search-bar">
    <i class="fa fa-search" aria-hidden="true"></i>
    <input id="search" type="text" placeholder="Search..." />
    <div id="search-result"></div>
  </div>
</div>

あとはてきとうなレイアウトに{% include search_bar.html %}とかして表示するようにしておく。

検索処理の作成

<script type="text/javascript">
  let posts = [];
  $(window).on('load', () => {
    $.get('/api/posts.json', {}, (data) => {
      posts = data;
    });
    $('#search').on('keyup', () => {
      const keyword = document.getElementById('search').value.toLowerCase();
      const searchResult = [];

      if (keyword.length > 0) {
        $('#search-result').show();
      } else {
        $('#search-result').hide();
      }
      $('.result-item').remove();

      for (let post of posts) {
        if (
          post.title.toLowerCase().indexOf(keyword) >= 0 ||
          post.text.toLowerCase().indexOf(keyword) >= 0
        ) {
          searchResult.push(post);
        }
      }
      if (searchResult.length === 0) {
        $('#search-result').append(
          '<div class="result-item"><div class="description">There is no search result.</div></div>'
        );
      } else {
        for (let result of searchResult) {
          $('#search-result').append(
            '<a class="result-item" href="' + result.url + '"><di class="title"> 【' + result.category + '' + result.title + '</div><div class="description">' + result.description + '</div></a>'
          );
        }
      }
    });
  });
</script>

以上でいけるでしょう。

事前にJSONファイルを作成しておいて、検索処理自体はクライアントサイドで全部実施するという仕組み。単純にキーワードを全文探索しているので、記事数量と本文の物量が増えれば重くなるのかもしれないが、今のところ特に問題なさそうなので、暫くこれでいこう。

< Liquidでまるっとエスケープする

Wordpressにさようなら >