CSS
JavaScript
初心者

jsでサジェストっぽい事をやってみた

会社のWEBにサジェスト機能を付けたくて、「サジェストができそうなライブラリ使っていいですか?」とお伺いをたてたら「駄目」と言われたので、初心者なりにjavascriptを勉強して作ってみました。駄目な点などありましたら、ぜひ教えてください。

必要なhtmlとcss

<input type="text" class="suggest_input -1"><br>
<div id="output" class="suggest_option dpnone"></div>
<style type="text/css">
.suggest_option{
  background-color: rgb(255, 255, 255);
  border: 1px solid rgb(162, 162, 162);
  border-width: 0px 1px 1px 1px;
  max-width: 140px;
  padding: 3px;
  font-size: 12px;
  position: absolute;
}
.suggest_input{
  display: inline-block;
}
.onmouse:hover{
  background-color: rgb(107, 151, 216);
}
.select{
  background-color: rgb(107, 151, 216);
}
.dpnone{
  display: none;
}
</style>

サジェスト候補を配列に格納する

function SuggestOption(){
  let Option = [
    'aaaa',
    'テスト',
    '2テスト',
    '',
  ];
  return(Option);
}

読み込み時のイベント

聞くところによると、addEventListenerでやるのがナウい方式らしいので、htmlにonclickで書くレトロ形式から脱却してみました。

window.addEventListener('load', function() {
  let SuggesJs =  document.getElementsByClassName('suggest_input');
  SuggesJs[0].addEventListener('keyup', SuggestJS, false);
})

サジェスト候補を絞り込む関数

function StrFilterTheAry(array, str){
  let SuggestOption = [];
  // let regexp = '/' + str + '(.*?)'  + ',/gmi';  //リテラルでできるパターンを考える//
  let regexp = new RegExp(str + '(.*?)', 'gmi');
  const map1 = array.filter(x => x.match(regexp)); //サジェスト候補を正規表現で評価
  for(let i = 0,length = map1.length; i < length; i++){
    SuggestOption[i] = map1[i];
  }
  return(SuggestOption)
}

最初に組んだ時は、汎用性のカケラもない構成だったのですが、4回ほど書き直すと多少改善した気がします。
regxp変数には正規表現リテラルを使いたいのですが、イマイチやりかたがわかりません。

メインの関数

function SuggestJS(ele){
  let SuggestOp = '', SuggestOpLeng, SelectLeng, Count, result;
  let KeyCode = ele.keyCode;
  let SuggestClass = document.getElementsByClassName('suggest_input');
  let SuggestArray = StrFilterTheAry(SuggestOption(), this.value);
  let SuggestPullDown = document.querySelector('.suggest_option');
  //サジェスト結果を成型してプリント//
  for(let i = 0, length = SuggestArray.length; i < length; i++){
    if(i === 0){
      SuggestOp += '<div class="onmouse">' + SuggestArray[i] + '</div>';
    }
    else if(i == length - 1){
      SuggestOp += '<div class="onmouse">' + SuggestArray[i] + '</div>';
    }
    else{
      SuggestOp += '<div class="onmouse">' + SuggestArray[i] + '</div>';
    }
  }
  document.getElementById('output').innerHTML = SuggestOp;
  console.log(SuggestOp);
  if(SuggestOp != ''){
    SuggestPullDown.classList.remove('dpnone');
  }else{
    SuggestPullDown.classList.add('dpnone');
  }

  //キーコードに応じて、フォーカスを移動しているように見せる//
    SuggestOp = document.querySelectorAll('.onmouse');
    SuggestOpLeng = SuggestOp.length;

    Count = SuggestClass[0].className.replace( /suggest_input/g , "" ) ;
    Count = Count.replace( / /g , "" ) ;
    Count = Number(Count);

    if( Count != -1){
      if(KeyCode === 40 && Count != SuggestOpLeng - 1){
        SuggestOp[Count].classList.remove('select');
        Count++;
        SuggestOp[Count].classList.add('select');
      }else{
        SuggestOp[Count].classList.add('select');
      }
      if(KeyCode === 38 && Count != 0){
        SuggestOp[Count].classList.remove('select');
        Count--;
        SuggestOp[Count].classList.add('select');
      }
    }else{
      SuggestOp[0].classList.add('select');
      Count = '0';
    }
    Count = String(Count);
    SuggestClass[0].classList.remove('-1', '0', '1', '2', '3', '4', '5', '6');
    SuggestClass[0].classList.add('suggest_input', Count);

  for(let i = 0; i < SuggestOpLeng; i++){
    //マウスオーバーの際にclass="select"を非表示にする//
    SuggestOp[i].addEventListener('mouseover', function() { 
      for(let i = 0; i < SuggestOpLeng; i++){
        SuggestOp[i].classList.remove('select');
      }
    }, false);
    //サジェストをクリックしたらinputに内容を入れてサジェストを削除する//
    SuggestOp[i].addEventListener('click', function() {
      document.querySelector('.suggest_input').value = this.innerHTML;
      for(let i = 0; i < SuggestOpLeng; i++){
        SuggestOp[i].classList.add('dpnone');
      }
      let a = document.querySelector('.suggest_option').classList.add('dpnone');

    }, false);
  }
}

キーボードの↓↑でサジェスト候補を移動するために、かなりコード量が増えました。矢印で移動するたびに移動した数値を記録してinputのclass=""に記載します。再度関数を実行する際にその数値を取得します。マウスオーバーによる選択もできるようにして、それを行った場合は矢印で選択する際に使用するclass="select"を消すようにしてあります。

とりあえず動作自体は問題ありませんでしたが、表示上限を設けていませんし、漢字のカナにも対応していません。改善していきたいですが、とりあえず今はこれでよしとしておきます。