各コンポーネントに保持するデータ
コンポーネント |
データ |
定義場所 |
備考 |
ルート(lineUp.js) |
商品データ |
dataオプション |
実際のアプリケーションでは外部から受けとる |
商品一覧(product-list.js) |
商品データ |
propsオプション |
親コンポーネント(lineUp.js)から受け取る |
検索条件 |
dataオプション |
子コンポーネント(product-header.js)に渡す |
ヘッダー(product-header.js) |
検索条件 |
propsオプション |
親コンポーネント(product-list.js)から受け取る |
表示件数 |
propsオプション |
親コンポーネント(product-list.js)から受け取る |
商品(product.js) |
商品データ |
propsオプション |
親コンポーネント(product-list.js)から受け取る |
※子は親のテンプレート内で使われるので、親より先に読み込まないとVue.jsが解析失敗してエラーになります。
ルートコンポネントのテンプレート
<div id="app">
<product-list v-bind:products="products"></product-list>
</div>
・・・・
・・・・
↓↓
<script src="../common/filter.js"></script>
<script src="components/product-header.js"></script>
<script src="components/product.js"></script>
<script src="components/product-list.js"></script>
<script src="../scripts/lineUp.js"></script>
</body>
ルートコンポネントのスクリプト
var app = new Vue({
el: '#app',
data: {
//商品リスト
products: [
{ id: 1, name: 'ジム<br>クライミング体験会', price: 1550, image: '../images/clim.jpg', delv: 0, isSale: true },
{ id: 2, name: 'ジム<br>クライミング観戦チケット', price: 1280, image: '../images/clim.jpg', delv: 0, isSale: true },
{ id: 3, name: '福岡会場<br>公式戦観戦チケット', price: 1680, image: '../images/clim.jpg', delv: 190, isSale: true },
{ id: 4, name: '外岩講習会<br>外岩クライミング体験チケット', price: 500, image: '../images/clim.jpg', delv: 0, isSale: true },
{ id: 5, name: 'リード<br>リードクライミング講習', price: 890, image: '../images/clim.jpg', delv: 0, isSale: false },
{ id: 6, name: 'ロープの使い方<br>クライミング座談会', price: 990, image: '../images/clim.jpg', delv: 0, isSale: false }
]
}
});
フィルターのスクリプト
//通貨書式に変換するフィルター
Vue.filter('number_format', function (val) {
return val.toLocaleString();
});
商品のコンポーネント
var product = {
template: `
<div class="item">
<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>
</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>`,
props: ['product']
};
ヘッダーのコンポーネント
var productHeader = {
template: `
<header>
<h1 class="pageTitle">商品一覧</h1>
<!--検索欄-->
<div class="search">
<div class="result">
検索結果<span class="count">{{ count }}件</span>
</div>
<div class="condition">
<div class="target">
<label>
<input type="checkbox"
v-bind:checked="showSaleItem"
v-on:change="$emit('showSaleItemChanged')">セール対象
</label>
<label>
<input type="checkbox"
v-bind:checked="showDelvFree"
v-on:change="$emit('showDelvFreeChanged')">送料無料
</label>
</div>
<div class="sort">
<label for="sort">並び替え</label>
<select id="sort" class="sorting"
v-bind:value="sortOrder"
v-on:change="$emit('sortOrderChanged', parseInt($event.target.value))">
<option value="1">標準</option>
<option value="2">価格が安い順</option>
</select>
</div>
</div>
</div>
</header>`,
props: ['count', 'showSaleItem', 'showDelvFree', 'sortOrder']
};
商品一覧コンポーネント
Vue.component('product-list', {
template: `
<div class="container">
<product-header
v-bind:count="filteredList.length"
v-bind:showSaleItem="showSaleItem"
v-bind:showDelvFree="showDelvFree"
v-bind:sortOrder="sortOrder"
v-on:showSaleItemChanged="showSaleItem=!showSaleItem"
v-on:showDelvFreeChanged="showDelvFree=!showDelvFree"
v-on:sortOrderChanged="sortOrderChanged">
</product-header>
<div class="br200"></div>
<div class="list">
<product
v-for="product in filteredList"
v-bind:product="product"
v-bind:key="product.id">
</product>
</div>
</div>`,
components: {
'product-header': productHeader,
'product': product
},
props: ['products'],
data: function () {
return {
showSaleItem: false,
showDelvFree: false,
sortOrder: 1
}
},
methods: {
//並び替えの選択が変わったときに呼び出されるメソッド
sortOrderChanged: function (order) {
this.sortOrder = order;
}
},
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 (isShow) {
newList.push(this.products[i]);
}
}
if (this.sortOrder == 1) {
//元の順番にpushしているので並び替え済み
} else if (this.sortOrder == 2) {
newList.sort(function (a, b) {
return a.price - b.price;
});
}
return newList;
}
}
});