Vue.js で要素をフィルタリングしてみた
投稿日:2017年07月25日
お疲れ様です、ナガです。
ブログ記事などをカテゴリでフィルタリングして、チェックボックスでチェックしたカテゴリに紐付いた記事を表示させたい…みたい要望がウェブサイト制作では結構あったりします。
いつもは html
に data-hoge="value"
を持たせて jQuery
でゴニョゴニョするみたいに書いていました。
Vue.js のナレッジを高める為にもここは一度 Vue.js で実装してみようかと思います。
Vueインスタンスを作成
JS
Vueをマウントする要素と、ダミーの記事データを準備します。
本来なら JSONで返ってくるAPIから、ajax
で記事を取得して、データ(今回のコードだと posts
)に突っ込むのかなぁ思いますが、今回は直書きします。
カテゴリリストもAPIで取ってこれたらよいのですが、取ってこれない場合は、ajax
で取得した記事データからカテゴリを持ってきて、重複してたら処理をスキップして〜…みたいな事をきっとやることになるとは思いますが、今回は直書きします。
チェックしているカテゴリを格納する preview
という空の配列をデータに用意します。
var vm = new Vue({
el: '#main',
data: {
posts: [
{
name: 'title1', // 記事のタイトル
url : '//www.example.com', // 記事のパーマリンク
categories: ['php'], // 紐付いてるカテゴリ(複数化)
display: true // 表示するか否かの boolean値
},
{
// ~省略~
}
],
category_lists: ['html','js','css','php'], // 全カテゴリ
preview: [] // チェックボックスでチェックしたカテゴリを格納する
}
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
html
category_lists
を for
で回して、カテゴリとチェックボックスを表示させます。
チェックしたカテゴリを preview
に入れるために v-model
でデータと紐付けます。
posts
に格納された記事データを for
で回して、表示させます。
v-show
に post.display
をバインドさせて、値が true
な記事のみ表示させます。
カテゴリリスト(categories
)は配列なので、更に for
で回して表示させます。
<div id="main">
<h1>カテゴリでフィルタリングするUI DEMO</h1>
<div>
<ul class="category_list">
<li v-for="category in category_lists">
<input type="checkbox"
v-bind:id="category"
v-bind:value="category"
v-model="preview">
<label v-bind:for="category">{{ category }}</label>
</li>
</ul>
</div>
<p>選択しているカテゴリ:{{ preview }}</p>
<ul class="entry_list">
<li v-for="post in posts" v-show="post.display">
<p><a v-bind:href="post.url">{{ post.name }}</a></p>
<ul><li v-for="category in post.categories">{{ category }}</li></ul>
</li>
</ul>
</div>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
これで、カテゴリ一覧のチェックボックスと記事の一覧が表示されました。
現状ではチェックボックスを選択してもフィルタリングされないので、フィルタリング用のメソッドを追加します。
フィルタリングさせる
JS
先ほどのJSに選択したカテゴリを記事から探してをフィルタリングする find_categories
というメソッドを追加します。
このメソッドでやっていることは、チェックしているカテゴリが1つ以上なら、フィルタリングする為の処理が発火します。
発火したら記事数だけ回します。
そして、チェックしたカテゴリの個数だけ再び回して、記事内にチェックしたカテゴリが含まれていたら表示(display:true
)、カテゴリが含まれていなかったら非表示(display:false
)にします。
チェックボックスが一つもチェックされていない時は全てを表示(display:true
)させます。
var vm = new Vue({
// ~省略~
methods: {
find_categories: function(){
var posts = this.posts;
var preview = this.preview;
if(preview.length > 0) {
for (var i = 0; i < posts.length; i++) {
var categories = posts[i].categories;
for (var j = 0; j < preview.length; j++) {
if(categories.indexOf(preview[j]) >= 0){
posts[i].display = true;
break;
} else {
posts[i].display = false;
}
}
}
} else {
for (var i = 0; i < posts.length; i++) {
var categories = posts[i].categories;
posts[i].display = true;
}
}
}
}
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
html
先ほどの find_categories
をチェックボックスが押下された時に発火させたいので、htmlを修正します。
v-on:click
(@click
でも可) に find_categories
を設定します。
これでチェックボックスを押下すると find_categories
が発火し、記事をフィルタリングしてくれます。
<div id="main">
<h1>カテゴリでフィルタリングするUI DEMO</h1>
<div>
<ul class="category_list">
<li v-for="category in category_lists">
<input type="checkbox"
v-bind:id="category"
v-bind:value="category"
v-model="preview"
v-on:click="find_categories">
<label v-bind:for="category">{{ category }}</label>
</li>
</ul>
</div>
<!-- 省略 -->
</div>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
DEMO
デモページを作ったのでご確認ください。
見た目もほとんどブラウザが持つデフォルトのスタイルですが…。
最後に
今まで jQuery
で頑張っていたことも、Vue.js を使うことによって、結構簡潔に書けるようになったのかなぁと思います。
htmlに直接テンプレートを書いて、データと切り分けができるのが、僕が感じる Vue.js の魅力の一つです。
しかし、今のままだと見た目がダサすぎるし、動きもないのであまり実用的ではありません…。
今度はフィルタリングにトランジション効果を付けて見栄えを良くして少しでも実用的なモノにします。
もっと勉強して Vue.js を実務レベルで扱えるように頑張りまーす。