javascriptでライブラリ無しでオートコンプリート
投稿日:
javascriptを使ってイチからオートコンプリートを実装しました。
オートコンプリートは何もなければライブラリを使って実装するのが早いですが、 イチから自分で実装する機会があったのでメモを残します。
要件
- PC(Chrome, IE, Safari), Android(Chrome), iPhone(safari)に対応する。
- 入力したキーワードを含む都道府県を選択肢として表示する。
- 選択肢をクリックしたら選択したこととする。
- PCでは選択肢からカーソルキー&エンターキーでも選択できるようにする。
この4つ目が肝です。
対応方法
こちらに動くものを用意してあります。
デモ
HTMLは以下のようになっているとします。
テキストボックスに文字を入力するとulタグ内に選択肢が表示されるようにします。
<input type="text" id="keyword" placeholder="都道府県名を入れてください" autocomplete="off"/>
<ul id="outputBox"></ul>
javascriptは以下の通りです。
// 都道府県一覧
const prefectureList = ['北海道','青森県','岩手県','宮城県','秋田県','山形県','福島県',
'茨城県','栃木県','群馬県','埼玉県','千葉県','東京都','神奈川県',
'新潟県','富山県','石川県','福井県','山梨県','長野県','岐阜県',
'静岡県','愛知県','三重県','滋賀県','京都府','大阪府','兵庫県',
'奈良県','和歌山県','鳥取県','島根県','岡山県','広島県','山口県',
'徳島県','香川県','愛媛県','高知県','福岡県','佐賀県','長崎県',
'熊本県','大分県','宮崎県','鹿児島県','沖縄県'];
// in/out要素を変数に入れておく
const inputElm = document.getElementById('keyword');
const outboxElm = document.getElementById('outputBox');
/**
* テキストボックスに文字入力時
*/
inputElm.addEventListener('compositionend', function(e) {
// タブキーは次の要素に移動させるのでスルー
if (e.key == 'Tab') {
return;
}
outboxElm.innerHTML = '';
let _this = this;
setTimeout(function(){
// 入力された文字を含む都道府県を抽出する
prefectureList.forEach(function(prefecture){
if (prefecture.indexOf(_this.value) != -1) {
let liElm = document.createElement('li');
liElm.setAttribute('tabindex', '0');
// 表示する選択肢にクリックイベントを設定する
liElm.onclick = function() {
// 選択肢をクリックしたらテキストボックスに反映する
inputElm.value = this.innerHTML;
outboxElm.innerHTML = '';
}
// キーワードを含む選択肢をulに追加する
let txtNode = document.createTextNode(prefecture);
liElm.appendChild(txtNode);
outboxElm.appendChild(liElm);
}
});
}, 10);
});
/**
* テキストボックスにフォーカスが当たっている時のキー操作
*/
inputElm.addEventListener('keydown', function(e) {
// 下キーを入力されたら選択肢の一番上にフォーカスを当てる
if (e.key == 'ArrowDown' || e.key == 'Down') {
let firstElm = outboxElm.getElementsByTagName('li')[0];
if (firstElm) {
firstElm.focus();
}
e.preventDefault();
}
});
/**
* 選択肢にフォーカスが当たっている時のキー操作 or Enter
*/
outboxElm.addEventListener('keydown', function(e) {
var currentElm = document.activeElement;
// 下キーを入力されたら次の選択肢にフォーカスを当てる
// ブラウザによりArrowDownだったりDownだったりする
if (e.key == 'ArrowDown' || e.key == 'Down') {
if (currentElm.nextElementSibling) {
currentElm.nextElementSibling.focus();
}
e.preventDefault();
}
// 上キーを入力されたら前の選択肢にフォーカスを当てる
// ブラウザによりArrowUpだったりUpだったりする
if (e.key == 'ArrowUp' || e.key == 'Up') {
if (currentElm.previousElementSibling) {
currentElm.previousElementSibling.focus();
}
e.preventDefault();
}
// Enterを入力されたら現在の選択肢をクリックした時と同じ挙動をする
if (e.key == 'Enter') {
currentElm.click();
}
});
これで基本的な挙動は実装できました。
なお、これだけではキーワードをBackspaceやDeleteで削除した際に選択肢を変更する処理は入っていません。
必要であればkeydown
イベント等を利用して文字削除時の処理を入れてください。