サイト制作に関するメモ書き

HOME > JavaScript > jQuery > jQueryでキーワード検索の機能を実装する

jQueryでキーワード検索の機能を実装する

CMSの記事情報をjsonで出力する前提で、json内の情報を検索する処理をjQueryで実装してみます。

サンプルコード

今回はこのようなjsonファイルを使って実装してみます。

{
  "data": [
    {
      "title": "約束のネバーランド",
      "body": "約束のネバーランドは、白井カイウ(原作)、出水ぽすか(作画)による日本の漫画作品。",
      "categories": ["2019", "冬", "サスペンス", "ファンタジー", "マンガ"],
      "url": "https://neverland-anime.com/"
    }, {
      "title": "私に天使が舞い降りた!",
      "body": "私に天使が舞い降りた!は、椋木ななつによる日本の漫画作品。",
      "categories": ["2019", "冬", "百合", "マンガ"],
      "url": "http://watatentv.com/"
    },
    ~ 略 ~
    {
      "title": "あそびあそばせ",
      "body": "あそびあそばせは、涼川りんによる日本の漫画。",
      "categories": ["2018", "夏", "ギャグ", "マンガ"],
      "url": "http://asobiasobase.com/"
    }
  ]
}

検索フォームは以下のようにします。

HTML

<form action="./" method="get">
  <input type="search" name="keyword" id="keyword">
  <button>送信</button>
</form>

formのactionに検索結果ページのURLを指定してください。
今回はフォームを設置するページと検索結果ページを同じページで実装します。

次に検索結果ページに結果を出力するエリアを用意します。

HTML

<div id="js-search-result">
  <p>検索キーワードを入力してください。</p>
</div>

#js-search-result内に結果を出力する想定です。

最後に検索処理をするJavaScriptです。

JavaScript

var paramKey = 'keyword'; // 検索キーワードとして取得するパラメータのキー
var jsonPath = 'data.json'; // 記事情報のjsonのパス
var jsonKeys = ['title', 'body', 'categories']; // 検索対象にするjson内のキー
var output = "#js-search-result"; // 検索対象にするjson内のキー

$(function(){
	// URLからキーワードを取得
	var s = get_search_keywords(paramKey);

	if(s) {
		// ajaxで記事情報を取得
		$.ajax({
			url: jsonPath,
			cache: false
		})
		.then(
			function (data) {
				// キーワードに一致する記事情報のインデックスを取得
				var index = keyword_search(data, s, jsonKeys);
				if(index.length >0) {
					// 検索結果一覧を生成
					generate_result(data, index);
				} else {
					alert('キーワードに一致する記事がありませんでした。');
				}
			},
			function () {
				console.log('取得に失敗しました。');
			}
		);
	} else {
		alert('キーワードが入力されていません。');
	}
});


/**
 * 検索に使用するキーワードを取得する
 * キーワードがない場合はfalseを返す
 * @param {string} key (required) パラメータのkey
 */
function get_search_keywords(key) {
	// URLからパラメータ取得
	var params = [];
	var param = location.search.substring(1).split('&');
	for(var i = 0; i < param.length; i++) {
		params[i] = param[i].split('=');
	}
	// キーワードを配列形式で格納
	var keywords = [];
	var separator =(/ | |\+/g);
	for(var i = 0; i < params.length; i++) {
		if(params[i][0] === key && params[i][1] !== undefined) {
			keywords = decodeURIComponent(params[i][1]).split(separator);
			break;
		}
	}
	// キーワードの値が空のものを除去
	keywords = keywords.filter(function(e){ return e !== ''; });
	// キーワードがない場合はfalseを返す
	if(keywords.length <= 0) {
		return false;
	}
	// キーワードを小文字に変換
	for(var i = 0; i < keywords.length; i++) {
		keywords[i] = keywords[i].toLowerCase();
	}
	return keywords;
}

/**
 * 記事内のキーワード検索
 * @param {object} articleData (required) 検索する記事情報
 * @param {array}  keywords    (required) 検索するキーワード
 * @param {array}  jsonKeys    (required) 検索対象にする記事情報のキー
 */
function keyword_search(articleData, keywords, jsonKeys) {
	var data = articleData['data'];
	var h = [];
	// 検索対象の値を配列にまとめる
	for (var i = 0; i < data.length; i++) {
		var v = [];
		for (var j = 0; j < jsonKeys.length; j++) {
			var thisVal = data[i][jsonKeys[j]];
			// 値が配列の場合はその各値を取得
			if(Array.isArray(thisVal)) {
				for (var k = 0; k < thisVal.length; k++) {
					v.push(thisVal[k].toLowerCase());
				}
			} else {
				v.push(thisVal.toLowerCase());
			}
		}
		h.push(v);
	}

	// 一致する配列のindexを取得
	var matchIndex = [];
	var matchCount;
	var thisArr;
	// 各記事のループ
	for (var i = 0; i < h.length; i++) {
		matchCount = 0;
		thisArr = h[i];
		// 検索キーワードでのループ
		for (var j = 0; j < keywords.length; j++) {
			// 記事の各項目でのループ
			for (var k = 0; k < thisArr.length; k++) {
				// 記事項目内に検索キーワードが含まれる場合
				if(thisArr[k].indexOf(keywords[j]) > -1) {
					matchCount++;
					break;
				}
			}
			// 検索キーワードが各項目に含まれなかった場合
			if(matchCount <= j) {
				break;
			}
			// 検索キーワードが全て記事に含まれていた場合
			if(matchCount >= keywords.length) {
				matchIndex.push(i);
			}
		}
	}
	return matchIndex;
}

/**
 * 検索に一致した記事で検索結果を生成
 * @param {object} articleData (required) 検索する記事情報
 * @param {array}  index       (required) 検索に一致する記事情報のindex
 */
function generate_result(articleData, index) {
	var data = articleData['data'];
	var ins = '';
	for (var i = 0; i < index.length; i++) {
		var t = index[i];
		ins += '<div class="article">';
			ins += '<h2 class="article_ttl">';
				ins += data[t]['title'];
			ins += '</h2>';
			ins += '<p class="article_body">';
				ins += data[t]['body'];
			ins += '</p>';
			ins += '<ul class="article_categories">';
				for(var j = 0; j < data[t]['categories'].length; j++) {
					ins += '<li>' + data[t]['categories'][j] + '</li>';
				}
			ins += '</ul>';
		ins += '</div>';
	}
	$(output).html(ins);
}

検索結果のデモページ
コード内にコメントで補足を入れているので詳細な説明は省略しますが、処理としては大きく3つに分かれていて、(1)検索に使用するキーワードを取得する、(2)記事内をキーワード検索する、(3)検索に一致した記事で検索結果を生成する、の流れになります。
 

“jQueryでキーワード検索の機能を実装する” への2件のフィードバック

  1. Bon より:

    大変参考になりました。
    ありがとうございます。

    検索ワードに完全一致したものだけ表示させたい場合には、
    どのようにしたら良いのでしょうか?

    勉強不足で申し訳ございませんが、ご教授頂ければと思います。
    どうぞ宜しくお願いいたします。

    • cly7796.net より:

      Bonさん
      コメントありがとうございます。
      記事のサンプルだとキーワードを含んでいる記事を表示するようになっているのですが、例えばtitleとキーワードが完全一致する記事のみ表示する、みたいなことでしょうか。
      サンプルのJavaScriptを少し変更してみましたが、こういったことでしょうか。
      http://cly7796.net/wp/sample/implement-keyword-search-function-with-jquery/index2.html
      3行目で検索対象をtitleのみに変更、110行目で完全に一致するかどうかを判定するようにしています。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

▲PAGE TOP