Vue入門の第12回(第1回はこちら)です。今回は、前々回までに作成した「靴下を買い物かごに入れるプログラム」を実際にコンポーネント化してみます。
現時点のプログラムを確認する
コンポーネント化の作業に入る前に、前々回までに作成した現時点のindex.htmlとmain.jsを確認しておきましょう。
現時点の index.html は、以下の通りです。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Vueサンプル</title>
<script src="https://unpkg.com/vue"></script>
</head>
<body>
<div id="app">
<div class="item">
<div class="item-image">
<img v-bind:src="itemImage" />
</div>
<div class="item-info">
<h2>{{ itemFullName }}</h2>
<ul><li v-for="itemInfo in itemInfos">{{ itemInfo }}</li></ul>
<p v-if="zaiko > 2">在庫あり</p>
<p v-else-if="zaiko <= 2 && zaiko > 0">残りわずか!</p>
<p v-else>在庫なし</p>
<div
v-for="itemColor in itemColors"
v-on:click="changeColor(itemColor.cImage, itemColor.cName)"
v-bind:style="{ backgroundColor: itemColor.cCode }"
style="width:30px; height:30px; margin-bottom:20px;"
>
</div>
<button
v-on:click="addCart"
v-bind:disabled="soldout"
>買い物かごの中身を増やす</button>
<div class="cart">
<p>買い物かごの中身 {{ cart }}</p>
</div>
</div>
</div>
</div>
<script src="main.js"></script>
</body>
</html>
現時点の main.js は、以下の通りです。
var app = new Vue({
el: '#app',
data: {
itemName: 'キッズ靴下',
itemColorName: 'ピンク',
itemImage: './images/socks-pink.png',
itemInfos: ["子供向け靴下", "コットン100%", "人気商品!"],
itemColors: [
{cName:"ピンク", cCode:"#ee6699", cImage:"./images/socks-pink.png"},
{cName:"ブルー", cCode:"#33aaee", cImage:"./images/socks-blue.png"}
],
zaiko: 5,
cart: 0,
soldout: false
},
methods: {
addCart: function () {
this.cart += 1
this.zaiko -= 1
if (this.zaiko <= 0) {this.soldout = true}
},
changeColor (cImage, cName) {
this.itemImage = cImage,
this.itemColorName = cName
}
},
computed: {
itemFullName() {
return this.itemName + '(' + this.itemColorName + ')'
}
}
})
以下は、上記プログラムの動作確認用のサンプルページです。 別画面で開きます。
https://programming-world.net/sample/vue_sample/10/index.html
Vueコンポーネントの書式を確認する
次に、前回学んだVueコンポーネントの書式を確認しておきましょう。
Vue.component('コンポーネント名', {
template: `
<div>
<h1>・・・</h1>
<p>・・・</p>
</div>
`,
data() {
return {
//dataプロパティ
}
},
methods: {
//methodsプロパティ
},
computed: {
//computedプロパティ
}
})
Vueコンポーネントを作成する際には、Vue.component(‘コンポーネント名’, { ~ }) でひとつのコンポーネントを定義します。
そして、{ ~ } のなかにオプションとしてtemplate、data()、methods、computedなどのプロパティを記述します。
main.jsを書き換える
では、前々回までに作成した「靴下を買い物かごに入れるプログラム」を実際にコンポーネント化していきましょう。
現時点のmain.jsのバックアップを残したうえで、main.jsを以下のように書き換えます。
Vue.component('item', {
/*
ここにtemplate、data()、methods、computed
などのプロパティを記述する
*/
})
var app = new Vue({
el: '#app'
/*
ここに記述されていたdata、methods、computedプロパティは、
上のitemコンポーネントに移動する
*/
})
Vue.component(‘item’, { ~ }) の部分がひとつのコンポーネントです。まだ「item」というコンポーネント名を指定しただけで、具体的なプロパティの記述はしていません。
上記コードは未完成ですが、var appから「靴下を買い物かごに入れるプログラム」の機能を、itemコンポーネントとして切り出しています。
main.jsを完成させる
上記コードのitemコンポーネント内に、これまでに作成したプログラムを流し込んでmain.jsを完成させます。
main.js を以下のように書き換えます。バックアップとして残しておいた旧main.jsからコピー&ペーストすると、効率よく書き換えられるでしょう。
Vue.component('item', {
template: `
<div class="item">
<div class="item-image">
<img v-bind:src="itemImage" />
</div>
<div class="item-info">
<h2>{{ itemFullName }}</h2>
<ul><li v-for="itemInfo in itemInfos">{{ itemInfo }}</li></ul>
<p v-if="zaiko > 2">在庫あり</p>
<p v-else-if="zaiko <= 2 && zaiko > 0">残りわずか!</p>
<p v-else>在庫なし</p>
<div
v-for="itemColor in itemColors"
v-on:click="changeColor(itemColor.cImage, itemColor.cName)"
v-bind:style="{ backgroundColor: itemColor.cCode }"
style="width:30px; height:30px; margin-bottom:20px;"
>
</div>
<button
v-on:click="addCart"
v-bind:disabled="soldout"
>買い物かごの中身を増やす</button>
<div class="cart">
<p>買い物かごの中身 {{ cart }}</p>
</div>
</div>
</div>
`,
data() {
return {
itemName: 'キッズ靴下',
itemColorName: 'ピンク',
itemImage: './images/socks-pink.png',
itemInfos: ["子供向け靴下", "コットン100%", "人気商品!"],
itemColors: [
{cName:"ピンク", cCode:"#ee6699", cImage:"./images/socks-pink.png"},
{cName:"ブルー", cCode:"#33aaee", cImage:"./images/socks-blue.png"}
],
zaiko: 5,
cart: 0,
soldout: false
}
},
methods: {
addCart: function () {
this.cart += 1
this.zaiko -= 1
if (this.zaiko <= 0) {this.soldout = true}
},
changeColor (cImage, cName) {
this.itemImage = cImage,
this.itemColorName = cName
}
},
computed: {
itemFullName() {
return this.itemName + '(' + this.itemColorName + ')'
}
}
})
var app = new Vue({
el: '#app'
})
上記コードは、前々回までに作成した「靴下を買い物かごに入れるプログラム」を、ほとんどコピー&ペーストで流し込んだだけですが、templateプロパティとdataプロパティの部分が若干異なります。
templateプロパティは、レンダリング用のテンプレートとなるHTMLタグを記述する部分です。これまではindex.html側で記述していたHTMLタグを、template: ` ~ ` のなかに記述しています。
dataプロパティは、戻り値を返す関数となっています。dataプロパティを関数にしておくことで、同じコンポーネントが複数利用される場合にもそれぞれ個別のdataインスタンスが生成されるようになります。
Vueコンポーネントにおけるtemplateプロパティやdataプロパティについては、前回も解説しています。合わせてご確認いただくと理解が深まるかもしれません。
index.htmlを書き換える
次に、index.htmlを以下のように書き換えます。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Vueサンプル</title>
<script src="https://unpkg.com/vue"></script>
</head>
<body>
<div id="app">
<item></item>
</div>
<script src="main.js"></script>
</body>
</html>
index.htmlの記述は大変スッキリしました。 <div id=”app”> ~ </div>をルート要素にして、そのなかに<item></item>という具合にitem要素がひとつだけ記述されています。
これまでindex.html内に記述していたHTMLタグを、main.js内のtemplate: ` ~ ` に移動させたため、index.html内に複雑なコードを記述する必要がなくなりました。
表示を確認してみる
ここまで出来たら、 index.htmlとmain.jsを上書き保存して表示を確認してみましょう。以下は、今回作成したサンプルページです。
https://programming-world.net/sample/vue_sample/12/index.html
前々回時点と同じように動作していれば成功です。
コンポーネントにすると再利用性が高まる
プログラムをコンポーネント化するメリットのひとつは、再利用性が高まることです。例えば、「靴下を買い物かごに入れるプログラム」をコンポーネント化したことで、複数の買い物かごをウェブページ内に簡単に配置できます。
以下の使用例では、itemコンポーネントを3つ並べています。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Vueサンプル</title>
<script src="https://unpkg.com/vue"></script>
</head>
<body>
<div id="app">
<item></item>
<item></item>
<item></item>
</div>
<script src="main.js"></script>
</body>
</html>
以下は、動作確認用のサンプルページです。別画面で開きます。
https://programming-world.net/sample/vue_sample/12/index3.html
同じ機能を持つ3つの買い物かごが作成できていれば成功です。
<item></item>というタグを3つ並べるだけで、3つの買い物かごが簡単に作成できました。dataプロパティの部分を戻り値を返す関数としているので、3つのitemコンポーネントはそれぞれ個別のデータを扱う独立した買い物かごとして動作します。コンポーネントが再利用できることを実感していただければ幸いです。
Vueでは、このようにウェブページをコンポーネント単位でモジュール化して、ブロックのパーツを組み合わせるようにしてアプリケーションを作成していきます。
次回へ続きます。