こちらが完成させたものです。皆さんもチャレンジしてみてください。
HTML
<div id=”app”>
<div class=”container”>
<h1 class=”pageTitle”>商品一覧</h1>
<!– 検索欄 –>
<div class=”search”>
<div class=”result”>
検索結果<span class=”count”>{{filteredList.length}}件</span>
</div>
<div class=”condition”>
<div class=”target”>
<label><input type=”checkbox” v-model=”showSaleItem“>セール対象</label>
<label><input type=”checkbox” v-model=”showDelvFree“>送料無料</label>
</div>
<div class=”sort”>
<label for=”sort”>並び変え</label>
<select id=”sprt” class=”sorting” v-model.number=”sortOrder“>
「.number」について。 セレクトボックスの入力値は文字列型になります。たとえ<option>タグのvalueを1や2といった数値にしても、これらは数値型でなく「数字」になり「文字列」となります。そのため、「.number修飾子」を使って、入力値を数値型に変換します。
<option value=”1″>標準</option>
<option value=”2″>価格が安い順</option>
</select>
</div>
</div>
</div><!–search–>
<!– ここから商品一覧 –>
繰り返す商品データは、dataオプションに「products」という名前の配列で定義したので、v-forを使ってバインドしています。v-forで宣言したproductには、productsの配列要素が繰り返しのたびに代入されます。
v-if、v-elseディレクティブは何らかの要素に対して指定する必要がありますが、<div>や<span>などを使うと、そのままタグまで出力されてしまうので、ここでは<template>を使っています。<template>はDOMに出力されない特殊なタグだからです。
<div class=”list”>
<!– アイテム1 –>
<div class=”item” v-for=”product in filteredList” v-bind:key=”product.id”>
「v-bind:key」について。 v-forで繰り返して出力する要素やv-ifとv-elseで表示を切り替える要素には、Vue.jsが1つ1つの要素を区別できるようにkey属性を指定します。keyには、区別したい要素間で重複のない固有の値を指定しなければいけません。例えるならば、商品個別についているJANコード(バーコード)そこで今回は商品データにそれぞれidを追加してます。
<figure class=”image”>
<template v-if=”product.isSale“>
<div class=”status”>SALE</div>
</template>
<img v-bind:src=”product.image” alt=””>
<figcaption v-html=”product.name“></figcaption>
「v-html」について。 商品名には、ページ上で改行させたい場所に<br>タグが含まれていますが、普通にバインドすると「<」「>」がエスケープ処理されるため、HTMLには「<br>」が出力されてしまいます。マスタッシュ{{ }}で埋め込んだデータはVue.jsが必ずエスケープ処理を行います。そこでV-htmlというディレクティブを使うことによって、そのままHTMLとして出力できます。
</figure>
<div class=”detail”>
<div class=”price”><span>{{product.price | number_format}}</span>円(税込み)</div>
<template v-if=”product.delv == 0″>
<div class=”shipping-fee none” >送料無料</div>
</template>
<template v-else>
<div class=”shipping-fee”> +送料{{product.delv | number_format}}円</div>
</template>
</div>
</div><!–item–>
</div><!–list–>
</div><!–container–>
</div><!–app–>
CSS
body {
background: #000;
color: #fff;
}
.container {
width: 960px;
margin:0 auto;
}
.pageTitle {
font-weight: normal;
border-bottom: 2px solid;
}
.search {
display: flex;
justify-content: space-between;
}
.search .target {
display: inline-block;
}
.search .target label {
margin-right: 15px;
}
.list {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.list::after {
content: “”;
display: block;
width: 250px;
}
.item {
flex: 0 1 250px;
margin-bottom: 30px;
}
.item .image {
position: relative;
text-align: center;
}
.item .image img {
width: 100%;
height: auto;
}
.item .status {
position: absolute;
border-radius: 50%;
width: 4em;
height: 4em;
font-size: 12px;
display: flex;
align-items: center;
justify-content: center;
background: #bf0000;
color: #fff;
}
.item .detail {
text-align: center;
}
.item .price {
display: inline-block;
}
.item .price span {
font-size: 180%;
}
.item .shipping-fee {
display: inline-block;
background: #f7cd12;
color: #000;
}
.item .shipping-fee.none {
background: #bf0000;
color:#fff
}
JavaScript
Vue.filter(‘number_format’,function(val){ return val.toLocaleString(); }) | 数値を通貨書式「#,###,###」に変換するフィルター。フィルターはそのフィルターを利用するコンポーネントよりも先に定義する。 |
var app = new Vue({ el:’#app’, data:{ | |
count: 0, | 表示中の商品数。一般に数値型の変数の初期値として使われる「0」を設定。 |
showSaleItem:false, | セール対象のチェック状態 true:チェック有り false:チェック無し |
showDelvFree: false, | 送料無料のチェック状態 true:チェック有り false:チェックなし |
sortOrder:1, | 並び替えの選択 1:標準 2:価格が安い順 |
products:[ {id:1,name:’Micheal<br>スマホケース’, price:1580, image:’01.jpg’, delv:0, isSale:true }, {id:2,name:’Raphael<br>スマホケース’, price:1580, image:’02.jpg’, delv:0, isSale:true }, {id:3,name:’Gabriel<br>スマホケース’, price:1580, image:’03.jpg’, delv:240, isSale:true }, {id:4,name:’Uriel<br>スマホケース’, price:980, image:’04.jpg’, delv:0, isSale:true }, {id:5,name:’Ariel<br>スマホケース’, price:980, image:’05.jpg’, delv:0, isSale:false }, {id:6,name:’Azrael<br>スマホケース’, price:1580, image:’06.jpg’, delv:0, isSale:false } ] }, | 商品リスト |
watch:{ | 絞り込み機能の監視。 |
showSaleItem: function(newVal, oldVal){ console.log(‘showSaleItemウオッチャーが呼び出されました’) }, | 「セール対象」チェックボックスの状態を監視 |
showDelvFree: function(newVal, oldVal){ console.log(‘showDelvFreeウオッチャーが呼び出されました’) } }, //watch | 「送料無料」チェックボックスの状態を監視 |
computed: { filteredList: function(){ | 絞り込み、並び替えの後の商品リストを元に返す算出プロパティ。 (絞り込み、並び替えでの表示対象外削除における復元作業) |
var newList = []; for (var i = 0; i < this.products.length; i++){ | 絞り込み後の商品リストを格納する新しい配列 |
var isShow = true; | 表示対象かどうかを判定 |
if (this.showSaleItem && !this.products[i].isSale){ isShow = false; } | セール対象チェックありで、セール対象商品ではない場合、この商品は表示しない |
if(this.showDelvFree && this.products[i].delv > 0){ isShow = false; } | 送料無料チェックありで、送料有りの商品の場合、この商品は表示しない |
if(this.sortOrder === 1){ } | 新しい配列を並び替える 元の順番にpushしているので並び替え済 |
else if (this.sortOrder == 2){ newList.sort(function(a,b){ return a.price – b.price; }); } | 価格が安い順に並び替える |
return newList; } //filteredList } // computed }) //var app; | 絞り込み後の商品リストを返す |
この本を参考に学び、完成させることができました。しかし、プログラミング初心者の私が詳しく解説することは、おこがましく、難しく出来ません(ToT) その点、この本では丁寧な解説が載っていますので、解説とともにコードを書き、完成させればより深く学ぶことができます(^.^) 身に付けて消えないスキルがこの値段。買っておいてよかったです。