シンプルなJSで作るサジェスト機能を解説
この記事は2023/03/31に作成されました。
サジェスト機能について
サジェスト機能とはユーザーが入力する予定のキーワードに対して、自動的に候補を表示する機能です。例としては、Googleの検索バーがあげられます。Googleの検索バーにキーワードを入力すると、検索バーの下に関連するキーワードが表示されます。この機能は、ユーザーが正確なキーワードやフレーズを入力する手間を省くだけでなく、入力が必要な情報を素早く提供することによって、UXを向上させることができます。
datalistでの実装例とできないこと
<datalist>
はHTML5で導入された要素で、ユーザーが入力する値の選択肢を提供するために使用されます。通常、テキスト入力フィールドと組み合わせて使用されます。
<label for="my-input">Choose a fruit:</label>
<input type="text" list="fruits" id="my-input" name="fruit">
<datalist id="fruits">
<option value="Apple">
<option value="Banana">
<option value="Cherry">
<option value="Date">
<option value="Elderberry">
</datalist>
軽く説明すると、datalist要素のid属性に指定した値をサジェスト検索するinput要素のlist属性に設定。
datalist要素の中にサジェストで表示する候補をoption要素で定義。HTML5の機能だけで以下のようなサジェストが表示されるようになりました。
しかしdatalistにも実現できないことがあります。
・柔軟にCSSを適用することができない(JSを併用することで見た目を変更することは可能)
・ブラウザごとに挙動の差がある
このようにJSとクラスを工夫して実装できるようです。複雑になってしまうので、最初からJSで実装してしまった方が分かりやすく、カスタマイズできるものが実現できます
suggest.jsについて
・サジェスト候補は読み込み時に取得したリストを使用すること
・ライブラリやプラグインに依存しないシンプルなライブラリ
からsuggest.jsというMITライセンスのライブラリを使用しました。
http://www.enjoyxstudy.com/javascript/suggest/
suggest.jsでの実装例
簡単に使い方を紹介。
1.エリア定義
<input id="text" type="text" name="fruit" value="" autocomplete="off">
<!-- 補完候補を表示するエリア -->
<div id="suggest"></div>
2.suggest.jsを読み込み
/js/suggest.jsに公式からダウンロードしたライブラリのjsファイルがあると仮定します。以下のように読み込んだらそれ以降に3の処理を記述してください。
<script src="js/suggest.js">
</script>
3.Suggestインスタンスを作成
<script>
const list = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry'];
new Suggest.Local("text", "suggest", list);
</script>
new Suggest.Local("text", "suggest", list,{interval:300});
第一引数(今回はtext)に入力タグのID属性or要素
第二引数(今回はsuggest)に候補を表示するタグのID属性or要素
第三引数(今回はlist)に候補の配列
第四引数に省略可能なオプション
デフォルトでは500msごとに検索を行いますが、オプションのintervalで調整可能です。
詳細は公式を確認ください。
suggest.jsをカスタマイズする
ここまでで標準のサジェスト機能を実装することができました。しかし、通常のselect要素のように選択肢と値を分けて設定することができません。なので、suggest.jsをカスタマイズして実現していきます。
JSなどで参照できるように最終出力として、動的に出力されるサジェスト候補の要素に対応する値をdata-value属性として設定します。
//index.js
const list = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry'];
var listValue = ['1', '2', '3', '4', '5'];
new Suggest.Local("text", "suggest", list, listValue, {interval:300});
第四引数にlistに対応した値の配列を設定するようにします。これを実現するためのsuggest.jsライブラリの変更はこちらです。
1.suggest.js(39行目付近)/初期化設定を変更
initialize: function (input, suggestArea, candidateList, valueList) {//(new)第四引数にvalueListを追加
this.input = this._getElement(input);
this.suggestArea = this._getElement(suggestArea);
this.candidateList = candidateList;
this.valueList = valueList;//(new)thisに設定
this.oldText = this.getInputText();
//if (arguments[3]) this.setOptions(arguments[3]);
if (arguments[4]) this.setOptions(arguments[4]);//オプションの受け入れを第5引数に変更
2.suggest.js(165行目付近)/選択要素を作成する関数を変更createSuggestArea
createSuggestArea: function (resultList, valueList = []) {//valueListを引数に受け入れる
this.suggestList = [];
this.inputValueBackup = this.input.value;
for (var i = 0, length = resultList.length; i < length; i++) {
var element = document.createElement(this.listTagName);
//--追加
//追加する選択要素にdata-value属性を追加。ここで選択要素へのカスタマイズを行うことができる。
if (typeof (valueList) !== 'undefined') {
element.setAttribute('data-value', valueList[i]);
}
//--
element.innerHTML = resultList[i];
this.suggestArea.appendChild(element);
3.suggest.js(107,121行目付近)/検索の関数を変更するsearch,_search
search: function () {
// init
this.clearSuggestArea();
var text = this.getInputText();
if (text == '' || text == null) return;
this.hookBeforeSearch(text);
var searchResult = this._search(text);//変更
var resultList = searchResult.resultList;//変更
var valueList = searchResult.valueList;//変更
if (resultList.length != 0) this.createSuggestArea(resultList, valueList);//第二引数に値配列を設定
},
_search: function (text) {
var resultList = [];
var valueList = [];//追加
var temp;
this.suggestIndexList = [];
for (var i = 0, length = this.candidateList.length; i < length; i++) {
if ((temp = this.isMatch(this.candidateList[i], text)) != null) {
resultList.push(temp);
valueList.push(this.valueList[i]);//選択肢配列に対応する値配列の値を格納
this.suggestIndexList.push(i);
if (this.dispMax != 0 && resultList.length >= this.dispMax) break;
}
}
return {resultList: resultList, valueList: valueList};//返却値を変更
},
これでサジェスト候補の要素にdata-value属性を設定完了です。値がdata-value属性に設定されているので、クリックイベント等をトリガーにして選択されたサジェスト候補の要素から値を取得して使うことができます。
まとめ
今回の例ではsuggest.jsを選定しましたが、Vue等のフレームワーク用のサジェストライブラリも存在しています。suggest.jsは少し古いライブラリなので、プロジェクトの要件によってはもっと良い選択肢があると思います。以上になります、ありがとうございました。
プログラマー/K.D