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)検索に一致した記事で検索結果を生成する、の流れになります。
はじめまして。
フロントのみで検索ツールができないかを探してこちらにたどり着きました。
とても参考になっております。ありがとうございます。
ご相談なのですが、
データのページネイションと総数を出したいと思っております。
の上部に『○○ の検索結果は ■■件です。』という検索結果の総数を出すことは可能でしょうか?
また、50件ごとにページネイションを出せますでしょうか。
前へ 1 2 3 次へ(全200件)
ご検討いただければ幸いです。
TOKIさん
コメントありがとうございます。
当ブログ内の別の記事でページネーションを追加したパターンを作成していますが、こういったことでしょうか。
総数の表示はなかったので、上記サンプルに総数表示を追加したパターンを用意しています。
https://cly7796.net/blog/sample/implement-keyword-search-and-pager-in-jquery/03/?keyword=マンガ
1ページ当たりの表示件数はsample.js 8行目のarticleCountで設定していますので、50件毎の場合はここの値を50としてください。
ありがとうございます!
イメージぴったりです!
申し訳ありません。ページネーションについて別に紹介されていたのを気づかず、お手数おかけしました。。。
理想の形にできました。お礼申し上げます。
再びの質問恐縮です。
ご相談したいのは上記のページ
> https://cly7796.net/blog/sample/implement-keyword-search-and-pager-in-jquery/03/?keyword=マンガ
こちらにand/or検索を追加することは可能でしょうか。
keyword_search 関数にOR検索を行うロジックを追加すればいいのかなあと
分岐処理をしてみたのですが、どうにもOR検索が作動せず…
ご指摘いただけると嬉しいです。。。
何度もお声掛けしてすみません。
どうぞよろしくお願いいたします。
TOKIさん
OR検索の処理を追加して、AND/OR検索を選択できるように追加してみましたが、こちらでどうでしょうか。
https://cly7796.net/blog/sample/implement-keyword-search-and-pager-in-jquery/04/?keyword=約束のネバーランド+五等分の花嫁&type=or
サイト内検索のとても良い勉強になりました。
ありがとうございます。
知識、勉強不足で大変恐縮ですが、検索後表示されたtitleをクリックし、jsonファイルにあるurlにページ移動させる事はできますでしょうか。
(約束のネバーランドをクリックするとhttps://neverland-anime.com/に移動など)
宜しければご教授いただければ幸いです。
kenkenさん
コメントありがとうございます。
下記で問題なさそうでしょうか。
https://cly7796.net/blog/sample/implement-keyword-search-function-with-jquery/index9.html
sample9.jsの140~142行目にリンクの設定を追加しています。
掲載データに関して質問させていただきます。
https://cly7796.net/blog/sample/implement-keyword-search-function-with-jquery/index6.html
上記は検索ワードのハイライト表示ですが、半角英語の大文字も敗退と表示対象とするにはどのようにすればよろしいでしょうか?
勉強不足で申し訳ございませんが、ご教授頂ければ幸いです。
何卒宜しくお願いいたします。
*コメントに誤植がありましたので返信にて再送させていただきます。
掲載データに関して質問させていただきます。
https://cly7796.net/blog/sample/implement-keyword-search-function-with-jquery/index6.html
上記は検索ワードのハイライト表示ですが、半角英語の大文字を含んだキーワードもハイライト表示の対象とするにはどのようにすればよろしいでしょうか?
勉強不足で申し訳ございませんが、ご教授頂ければ幸いです。
何卒宜しくお願いいたします。
Nerdさん
コメントありがとうございます。
大文字と小文字を区別しないようにしていたのを区別するように変更しましたが、こちらでどうでしょうか。
https://cly7796.net/blog/sample/implement-keyword-search-function-with-jquery/index8.html
ありがとうございます!イメージ通りの検索結果となりました。ご教示ありがとうございました。
(改めてコメント投稿させていただきます)
上記コメントのindex7の件でお世話になりました。
1点ご報告です。
当スクリプト(記事で公開されている一番最初のスクリプト)をヘテムル、さくらでテストしたところ問題なく動いているのですが、CPIでは動きませんでした。chrome開発者ツールのConsoleで確認したところ以下のようなエラーが出ております。
jquery-3.3.1.min.js:2
jQuery.Deferred exception: Cannot read properties of undefined (reading ‘length’) TypeError: Cannot read properties of undefined (reading ‘length’)
at keyword_search (https://***.***.com/sample1/sample.js:81:27)
at Object. (https://***.***.com/sample1/sample.js:19:17)
at l (https://code.jquery.com/jquery-3.3.1.min.js:2:29375)
at c (https://code.jquery.com/jquery-3.3.1.min.js:2:29677) undefined
宝屋さん
エラー内容のみなので推測ですが、ajaxで取得したデータに問題があってエラーが出ているように見えます。
コメント失礼します
CMS検索で高機能に使える物はないか探していたら、
こちらのスクリプトがかなり近いイメージなのでテストしています。
質問ですが”categories”に設定されたワードを検索する際、
テキストボックス内に自由記入ではなく
チェックボックスにして選択して対応する事は可能でしょうか。
takaraさん
コメントありがとうございます。
サンプル作成しましたが、以下のような形でしょうか。
https://cly7796.net/blog/sample/implement-keyword-search-function-with-jquery/index7.html
ほぼイメージにぴったりです!
これに、最初に公開されたバージョンに入っている「テキストボックス」を組み合わせても大丈夫でしょうか。
フリーワード入力とチェックボックス入力を用意したいと考えています。
度々すみません。
先ほどコメントしたテキストボックスとチェックボックスを並列できないかという事については、テキストボックスにname=”categories”を付けたうえで、categoriesの中にbodyの内容を転載する事で対応できそうなので(スマートなやり方ではないかもしれませんが・・・)、先ほどの質問はカットして頂いても構いません。お手数をおかけいたします。
他の方の改造(画像を入れる)なども入れてみて、改修を続けています。
アドバイスを頂きありがとうございました。
初めまして。サイト内検索を探してこちらの記事にたどり着きました。こちらの(https://cly7796.net/blog/sample/implement-keyword-search-function-with-jquery/index4.html)
スクリプトを使わせていただきたいのですが、以下のことはどうすれば可能でしょうか。
・キーワードをハイライト(span class=”highlight”で囲む)
・キーワードを含む4行ほどを出力
ご助力いただけますと助かります。
Sanaさん
コメントありがとうございます。
ハイライトは以下のような形で問題ないでしょうか。
https://cly7796.net/blog/sample/implement-keyword-search-function-with-jquery/index5.html
「キーワードを含む4行ほどを出力」については結果で出力する内容にもよりますので、sample5.jsのgenerate_result()内でHTMLを適宜調整いただく形になるかと思います。
ご返信とデモページをありがとうございます。思ったようにハイライトされ、本当に嬉しいです。
すみません、質問が不十分だったのですが、generate_resultのをCSSで4行のみ表示させることは出来たのですが、そうするとキーワードの位置に関わらず上から4行のみ抜き出してしまい、キーワード前後4行を表示することは叶いませんでした。
キーワード前後4行ほど(前後30字程度)抜き出すにはどうすればいいでしょうか。
調べても思ったような結果は得られず、お力を貸していただければ大変助かります。
どうぞよろしくお願いいたします。
Sanaさん
bodyの内容を30文字抜き出したいということでしょうか?
body内の最初のキーワードから30文字だけ抜き出すようにしましたが、こちらであっているでしょうか。
https://cly7796.net/blog/sample/implement-keyword-search-function-with-jquery/index6.html
思ったように実装できました!
細かい指定だったにも関わらずお助けくださり本当にありがとうございます。大変助かりました。
掲載データに関して質問させていただきます。
上記データを、自身のPC上でのみ(オフライン環境)で利用しようと思い、いろいろと試してみましたがJSONファイルのオフライン活用はできないようでした。
データ元のJSONファイルをJSファイル等に書き直して??、上記プログラムをオフラインでも使うことができるのでしょうか?
知識が乏しく恐縮ですが、よろしければご教授のほどよろしくお願いいたします。
TOMさん
コメントありがとうございます。
おそらくAjaxでJSONを取得するところで失敗しているのかと思います。
データ自体をjsの変数に入れる形であればよいかと思いますが、こちらでどうでしょうか。
https://cly7796.net/blog/sample/implement-keyword-search-function-with-jquery/index4.html
コメント失礼いたします
こちらのサンプルを参考にし様々な改良を行い導入したいのですが
検索結果の各欄に画像を表示させる事はできますか?
(約束のネバーランドならその画像、私に天使が舞い降りたならその画像)
画像を表示させるとしてどこをどの様に変更及び追記を行えば良いですか?
パルパルさん
コメントありがとうございます。
サンプルを作成してみましたが、こちらで問題なさそうでしょうか。
https://cly7796.net/blog/sample/implement-keyword-search-function-with-jquery/index3.html
jsonファイルに画像パスの項目を追加、sample3.jsの142行目で画像を追加するようにしています。
https://cly7796.net/blog/sample/implement-keyword-search-function-with-jquery/data2.json
https://cly7796.net/blog/sample/implement-keyword-search-function-with-jquery/sample3.js
ありがとうございます
その他例えばアニメや漫画のタイトルをリンクにしたりレイアウトを変える場合は結果出力部分を書き換えればよいですか?
そうですね、レイアウトの変更は sample3.jsの138~151行目が結果出力部分になりますので、こちらのHTMLを適宜書き換えれば変更できます。
大変参考になりました。
ありがとうございます。
検索ワードに完全一致したものだけ表示させたい場合には、
どのようにしたら良いのでしょうか?
勉強不足で申し訳ございませんが、ご教授頂ければと思います。
どうぞ宜しくお願いいたします。
Bonさん
コメントありがとうございます。
記事のサンプルだとキーワードを含んでいる記事を表示するようになっているのですが、例えばtitleとキーワードが完全一致する記事のみ表示する、みたいなことでしょうか。
サンプルのJavaScriptを少し変更してみましたが、こういったことでしょうか。
https://cly7796.net/blog/sample/implement-keyword-search-function-with-jquery/index2.html
3行目で検索対象をtitleのみに変更、110行目で完全に一致するかどうかを判定するようにしています。