Vue.jsでフォームに入力したテキストでフィルターをかける方法

フォームに入力したテキストでフィルター

Vue.jsでフォームに入力したテキストでフィルターをかけたいことがよくある。

例えば['Apple', 'Banana', 'Cookie']というデータがあって「an」と入力するとBananaだけが表示されるなどだ。

// <li v-for="food in foods">{{ food }}</li>
new Vue({
  el: '#app',
  data: {
    foods: ['Apple', 'Banana', 'Cookie'],
  }
})

Vue.jsでフォームに入力したテキストでフィルターをかけるサンプル

v-modelとcomputedでフィルター作成

Vue.jsにはv-filterみたいな追加するだけでフィルターができるような機能はないため、v-modelとcomputedを使って自分でフィルター作成する必要がある。

作成といってもdataにfilterText: ''を追記したあとcomputedに関数の処理を1行書いて、v-forに関数名を入れるだけなので簡単だ。

やり方はまずdataにfilterText: ''を追記したあと、その下にcomputedを追加してfilterFoods()のような適当な名前を入れる。

そしたらデータ(配列)をthis.foods.filterを使い、match(this.filterText)にマッチするものを返すだけだ。

// <input v-model="filterText">
// <li v-for="food in filterFoods">{{ food }}</li>
new Vue({
  el: '#app',
  data: {
    foods: ['Apple', 'Banana', 'Cookie'],
    filterText: ''
  },
  computed: {
    filterFoods() {
        return this.foods.filter(v => v.match(this.filterText))
    }
  }
})

Vue.jsでフォームに入力したテキストでフィルターをかけるサンプル

フィルターで大文字・小文字を区別しない

フィルターをかける際に英語の場合は大文字・小文字を区別したくない時がある。

その場合はnew RexExpで大文字・小文字を区別しないiオプションを追加したものをmatchに入れる。

new Vue({
  el: '#app',
  data: {
    foods: ['Apple', 'Banana', 'Cookie'],
    filterText: ''
  },
  computed: {
    filterFoods() {
      const reg = new RegExp(this.filterText, 'i')
      return this.foods.filter(v => v.match(reg))
    }
  }
})

Vue.jsでフォームに入力したテキストでフィルターをかけるサンプル2

データが配列オブジェクトの場合

データが配列オブジェクトの場合は前述の通りに返すとオブジェクトを返してしまう。

そのため、オブジェクトの場合はfilter使用時にkeyを指定してv.name.match()でマッチさせる。

ただし、このまま返すとオブジェクトがそのまま返ってしまうため、keyのvalueを返す場合はfilterに.map(v => v.name)をつなげて必要な値だけを返すようにする。

new Vue({
  el: '#app',
  data: {
    players: [
      {
        "age": 24,
        "name": "Ryu"
      },
      {
        "age": 24,
        "name": "Ken"
      },
      {
        "age": 25,
        "name": "Guile"
      }
    ],
    filterText: ''
  },
  computed: {
    filterPlayers() {
      const reg = new RegExp(this.filterText, 'i')
      return this.players.filter(v => v.name.match(reg)).map(v => v.name)
    }
  }
})

Vue.jsでフォームに入力したテキストでフィルターをかけるサンプル3

フィルターで一致するテキストに色を追加

フィルターで一致するテキストに色を追加したい場合はreplaceでタグで囲んで返す。

ただし、タグを返す場合はそのままだと&lt;のようになってしまうため、生のHTMLを入れる場合はv-htmlで入れる。

v-modelで取得したテキストをv-htmlにそのまま入れるのは危険なので、英数字以外は処理しないなどの記述も別途必要。

// <li v-for="player in filterPlayers" v-html="player"></li>
new Vue({
  el: '#app',
  data: {
    players: [
      {
        "age": 24,
        "name": "Ryu"
      },
      {
        "age": 24,
        "name": "Ken"
      },
      {
        "age": 25,
        "name": "Guile"
      }
    ],
    filterText: ''
  },
  computed: {
    filterPlayers() {
      if (!/^\w+$/.test(this.filterText) && this.filterText !== '') return
      const reg = new RegExp(this.filterText, 'i')
      return this.players.filter(v => v.name.match(reg)).map(v => {
        return  v.name.replace(reg, '<b style="color: red;">$&</b>')
      })
    }
  }
})

Vue.jsでフォームに入力したテキストでフィルターをかけるサンプル4