2017/04/12
javascriptフレームワークのvue.jsを使ってみる②(ソート機能っぽいもの)
以前、vue.jsの記事を書いたのですが、
今回もうちょっと機能を使い、DEMOを作ってみました。
前回は入門編と書いたのですが、基礎編とか応用編とか、ちょっとどう切り分けたらよいかわからなくなりそうなのでやめました笑
javascriptフレームワークのvue.jsを使ってみる(入門編)
今回のDEMOは「ECサイトでソートする機能みたいなもの」です。
公式サイトにある例のグリッドコンポーネント – Vue.js
価格、レビュー、口コミ数等をクリックすると順番が、昇順、降順で切り替わるようになっています。
あとはテキストフィールドに文字を入力するとその文字が入ったものを表示します。
コード
html
1 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 | <div id="sort"> <p>検索: <input type="text" name="query" v-model="word"></p> <table> <thead> <tr> <th></th> <th @click="sortBy('name')" >商品名</th> <th v-on:click='sortBy("price")' :class="['sortable',{active: sortKey == 'price' }]" >価格<span :class="sortOrders['price'] > 0 ? 'asc' : 'desc'">▼</span></th> <th v-on:click='sortBy("review")' :class="{ active: sortKey == 'review' }" class="sortable">レビュー<span :class="sortOrders['review'] > 0 ? 'asc' : 'desc'">▼</span></th> <th v-on:click='sortBy("viral")' :class="{ active: sortKey == 'viral' }" >口コミ数<span :class="sortOrders['viral'] > 0 ? 'asc' : 'desc'">▼</span></th> <th v-on:click='sortBy("regist")' :class="{ active: sortKey == 'regist' }" >登録日<span :class="sortOrders['regist'] > 0 ? 'asc' : 'desc'">▼</span></th> </tr> </thead> <tbody> <tr v-for="item in filteredData"> <td><img :src="item.img" alt=""></td> <td>{{item.name}}</td> <td>{{item.price}}円</td> <td>{{item.review}}</td> <td>{{item.viral}}</td> <td>{{item.regist}}</td> </tr> </tbody> </table> </div> |
javascript
1 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 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | var columnsData = { colmuns: ['name','price','review','viral','regist'], items:[ {img:"1.jpg",name: "メイソンジャー",price:1000,review:"3.5",viral:20,regist:"2017-1-1"}, {img:"2.jpg",name: "防水ケース",price:900,review:"3.0",viral:10,regist:"2017-2-1"}, {img:"3.jpg",name: "ワイングラス",price:800,review:"2.0",viral:3,regist:"2016-2-1"}, {img:"4.jpg",name: "テープ",price:1200,review:"2.5",viral:2,regist:"2016-10-23"}, {img:"5.jpg",name: "スマホケース",price:2000,review:"5.0",viral:39,regist:"2017-2-9"}, {img:"6.jpg",name: "カギ",price:500,review:"2.0",viral:0,regist:"2017-2-9"}, {img:"7.jpg",name: "小物入れ",price:1500,review:"5.0",viral:100,regist:"2017-4-9"}, {img:"8.jpg",name: "鏡",price:1100,review:"1.0",viral:0,regist:"2017-3-20"} ], sortOrders : function(){ var sortOrder = {}; columnsData["colmuns"].forEach(function (key) { sortOrder[key] = 1 }) return sortOrder; } }; new Vue({ el: '#sort', //データの設定 data: { colmuns: columnsData.colmuns, //項目 items:columnsData.items, //項目のデータ sortKey : "", //ソート対象 sortOrders : columnsData.sortOrders(), //ソートの値 word: "" //検索テキスト }, computed: { //dataの値が変更されるとfilteredDataが動作する filteredData: function(){ var data = this.items; var sortKey = this.sortKey; var wordKey = this.word && this.word.toLowerCase(); var order = this.sortOrders[sortKey] || 1; //検索テキストがある場合 if (wordKey) { data = data.filter(function (row) { return Object.keys(row).some(function (key) { return String(row[key]).toLowerCase().indexOf(wordKey) > -1 }) }) } //ソートが選択されている場合 if (sortKey) { data = data.slice().sort(function (a, b) { a = a[sortKey] b = b[sortKey] return (a === b ? 0 : a > b ? 1 : -1) * order }) } return data; } }, methods: { //ソート対象、ソートの値を変更する sortBy: function (key) { this.sortKey = key; this.sortOrders[key] = this.sortOrders[key] * -1; } } }); |
使用しているタグ(API)と実際にDEMOで仕様している例を使い簡単に説明します。
まずは、ディレクティブになります。
ディレクティブとは、主にhtmlに設定するもので、値が変更になった時反映させるための記述になります。
基本的にはv-で始まるものになります。
複数用意されているのですが、今回はDEMOで仕様した4つのみの紹介になります。
v-on
要素にイベントリスナーを設定するものです。
1 | <th v-on:click='sortBy("price")' :class="['sortable',{active: sortKey == 'price' }]" >価格<span :class="sortOrders['price'] > 0 ? 'asc' : 'desc'">▼</span></th> |
この場合、thをクリックすると、sortByという関数が呼び出されるということになります。
このsortBy関数は、methodsに記述されています。
ちなみに、
1 | <th @click="sortBy('name')" >商品名</th> |
このように記述してありますが、これはv-onを省略した形になります。
v-bind
公式には 「1つ以上の属性またはコンポーネントのプロパティと式を動的に束縛します。」とありますが、
いまいちよくわからないとも思います。
vueのdataの値により、動的に変更される値を付与するみたいな感じでしょうか。。。
1 | <th v-on:click='sortBy("viral")' :class="{ active: sortKey == 'viral' }" >口コミ数<span :class="sortOrders['viral'] > 0 ? 'asc' : 'desc'">▼</span></th> |
いきなり省略した形で書いてありますが、
1 | :class="{ active: sortKey == 'viral' }" |
がv-bindの記述になります。(省略しないと、v-bind:class=”” になります)
これは、class属性をdataのsortKeyが’viral’だった場合、activeを付与するという記述になります。
このclassですが、動的なactiveだけじゃなく、元々付けたいという場合は、
1 | :class="['sortable',{active: sortKey == 'price' }]" |
という形か(配列・オブジェクト形式で記述することができます。)、
普通に、class=”sortable”を書いてしまって大丈夫です。
1 | <th v-on:click='sortBy("review")' :class="{ active: sortKey == 'review' }" class="sortable">レビュー<span :class="sortOrders['review'] > 0 ? 'asc' : 'desc'">▼</span></th> |
v-for
これは繰り返しの記述で、foreach文とfor文とかみたいな感じです。
1 2 3 4 5 6 7 8 | <tr v-for="item in filteredData"> <td><img :src="item.img" alt=""></td> <td>{{item.name}}</td> <td>{{item.price}}円</td> <td>{{item.review}}</td> <td>{{item.viral}}</td> <td>{{item.regist}}</td> </tr> |
computedのfilteredDataのデータを表示しています。
基本は、{{}}で囲い表示させるのですが、
v-bindで表示する時は、{{}}は必要ありません。
v-model
こちらは、input要素,textarea等で使用することが主になるようですが、
記入した情報を送り、変化があった場合、受け取る記述になります。
1 | <p>検索: <input type="text" name="query" v-model="word"></p> |
今回はこのテキストは記入でしか変更されないので一方向的な感じになりますが、
このinputに記載した情報が、dataのwordにその情報が登録され、その登録された情報がこのinputの値に挿入される形になります。
(今回初期が空になっていますが、なにかテキストを入れてみると最初からその文字が入るようになります)
次は、script部分、Vueインスタンス部分の紹介になります。
el
公式では、「既存の DOM 要素に Vue インスタンスを与えます。CSS セレクタの文字列、実際の HTML 要素をとることができます。」
とありますが、
どこの要素でvueを動かしたいかというのを記述します。
今回は、id=”sort”の中なので、
1 | el: '#sort' |
と記述します。
data
表示させる情報や、変更させる元の情報を記載しておく場所です。
このdataを元に、computed,methods等で処理していきます。
1 2 3 4 5 6 7 | data: { colmuns: columnsData.colmuns, //項目 items:columnsData.items, //項目のデータ sortKey : "", //ソート対象 sortOrders : columnsData.sortOrders(), //ソートの値 word: "" //検索テキスト }, |
ちょっとよくわからないのですが、基本的には、このdataの中で、状態を変えたりするような処理はしない方が良いみたいです。
なので、今回dataは、vueの外側でobject(columnsData)で設定したものを読み込んでいます。
computed
公式では「Vue インスタンスに組み込まれる算出プロパティ」とあり、よくわからないのですが、
この中に記述したものは、使用しているdataが変更されると自動で更新されるようです。
つまり、
1 2 3 4 | filteredData: function(){ var data = this.items; //以下略 } |
使用しているitemsが変更された場合、filteredDataの処理が実行されるということだと思います(たぶん…)
ちなみに、このthisというは、dataを指すことになります。
この文では、dataの中のitemsの値を変数dataに定義、ということになります。
このfilteredDataが処理されると、html側に書いたv-forのfilteredDataに反映され、
動的にソートされるということになります。
methods
公式では、「Vue インスタンスに組み込まれるメソッドです。」とありますが、
私としては、Vueの情報を扱える関数を設定しておける場所という認識でいます。
html側からv-onで呼び出すこともできます。
1 2 3 4 | sortBy: function (key) { this.sortKey = key; this.sortOrders[key] = this.sortOrders[key] * -1; } |
ここのthisもdataを指しています。
このdemoでは、ソートの発火を担っており、
流れとしては、
- 見出し部分をクリックする
- このsortByが処理される
- dataのsortKeyとsortOrdersが変更される
- dataの値が変わったので、filteredDataが処理される
- htmlのfilteredDataが更新される
という感じになります。
おまけ
本日でvistaのサポートが終了になりました。
ということは…IE9を考慮しなくてすみます!!
すぐという訳にはいかないだろうと思いますが、その流れは加速していくことでしょう!
嬉しい限りです。
考慮しなくてすむとなるということは…
Flexbox
CSSアニメーション
を使用できる!!
ということです。
制作時、ブラウザ対応の仕様をしっかり決めて、IE11以上になれば、
堂々と使えるようになりますね!
Author Profile
スターフィールド編集部
SHARE