Vue.js①・データバインディング
Vue.js
Vue.jsは,JavaScriptフレームワークの一つであり,フロントエンドの開発に用いられます. フレームワークとは,Webアプリの骨組みとしての役割を担い,データを同期させる データバインディング ,ウェブページの部品となる コンポーネント などの機能が提供されます. JavaScriptフレームワークには,Vue.js以外にも,React,Angularなどがありますが,その中でもVue.jsは学習コストが低く,ページの一部分から大規模な開発まで手軽に利用できることが強みです. また,Vue.jsは日本での導入事例が比較的多く,日本語で書かれたドキュメントも豊富にあります(任天堂の公式サイトはVue.jsで開発).
- Vue.js 2014年にEvan You氏がリリース.MITライセンス.
- React 2013年にJordan Walke氏がリリース.MITライセンス.
- Angular 2016年にGoogleを中心としたコミュニティがリリース.MITライセンス.
CodePenの準備
CodePenにアクセスして,Penを作成し,タイトルを設定しましょう. Penのタイトルは「Chapter8」に設定しましょう.
ここでVue.jsのライブラリをペンに追加します. Settingsのウィンドウを開き,JS(JavaScript)のAdd External Scripts/Pensで,「Vue.js」を検索します. 検索結果の一覧から,バージョン2.6.11のVue.jsのCDN(Content Delivery Network)を追加します. CDNはライブラリなどに対するアクセスの集中を分散させる仕組みになっています.
Vue.jsの基本構造
Vue.jsの基本構造として次のように記述します.
HTMLでは,div
タグにID属性(id="app"
)を設定します.
JavaScriptでは,Vue
クラスのインスタンスを作成します.
引数は連想配列で与えられ,el
,data
,methods
などのオプションを指定します.
elでは,対応するdivタグのID属性を指定します. dataでは,次節で説明するデータバインディングのための変数を定義します. データバインディングとは,JavaScriptで宣言した変数を,HTMLで同期させる仕組みです. methodsでは,ボタンをクリックしたなどのイベントが発生したタイミングで実行する関数を定義します.
<!-- HTML -->
<div id="app">
<div>
// JavaScript
let app = new Vue({
el: "#app", // 対象のID属性を指定
data: {
// 変数を定義
},
methods: {
// 関数を定義
},
})
データバインディング
データバインディングを利用して,ページのタイトルと説明文を記述しましょう.
data
オプションに,title
とdescription
を連想配列の形式で記述します.
これらは,リアクティブデータと呼ばれ,データの更新がHTMLにも自動的に反映されます.
// JavaScript
let app = new Vue({
el: "#app",
data: {
title: "数字当てゲーム",
description: "指定された数字と同じ数のトランプを選んでください."
},
methods: {
},
})
次に,タイトルを表すh1
タグと,説明文を表すp
タグをHTMLに追加します.
このとき,data
オプションで定義したtitle
とdescription
を参照します.
参照するには マスタッシュ記法 に従って{{ title }}
,{{ description }}
のように記述します.
ちなみにマスタッシュ(Mustache)とは口髭のことです.
<!-- HTML -->
<div id="app">
<h1>{{ title }}</h1>
<p>{{ description }}</p>
<div>
マスタッシュ記法は,属性のデータバインディングに用いることができません.
この場合は,v-bind
ディレクティブと呼ばれる方法を用います.
先程と同様に,data
オプションに,title_color
を定義します.
title_color
には,文字色を緑に変更するためのCSSであるcolor: green
を代入します.
// JavaScript
let app = new Vue({
el: "#app",
data: {
title: "数字当てゲーム",
description: "指定された数字と同じ数のトランプを選んでください.",
title_color: "color: green",
},
methods: {
},
})
次に,h1
タグの属性style
に,v-bind
ディレクティブを指定します.
これにより,style="color: green"
が,h1
タグに適用されることになります.
<!-- HTML -->
<div id="app">
<h1 v-bind:style="title_color">{{ title }}</h1>
<p>{{ description }}</p>
<div>
キーポイント
- 要素のデータバインディングには マスタッシュ記法
- 属性のデータバインディングには v-bindディレクティブ
ボタン・イベントの処理
data
オプションに,カードの番号を表すnumber
を定義します.
また,methods
オプションに,ランダムにカードの番号を設定するshuffleCards()
を定義します.
shuffleCards()
は,1から3までの整数をランダムに生成し,number
に代入します.
このとき,変数名の前に this. を付けて,this.number
のように表します.
// JavaScript
let app = new Vue({
el: "#app",
data: {
title: "数字当てゲーム",
description: "指定された数字と同じ数のトランプを選んでください.",
title_color: "color: green",
number: 1,
},
methods: {
shuffleCards(){
// 1から3までの整数をランダムに設定
this.number = Math.floor(Math.random() * 3) + 1;
}
},
})
次に,シャッフル・ボタンを表すbutton
タグと,ランダムに設定されたnumber
を表示するp
タグを追加します.
button
タグには,v-on
ディレクティブを用いて,ボタンをクリックしたときにshuffleCards()
を実行するように設定します.
ボタンをクリックすると,カードの番号がランダムに変更されることを確認してください.
<!-- HTML -->
<div id="app">
<h1 v-bind:style="title_color">{{ title }}</h1>
<p>{{ description }}</p>
<button v-on:click="shuffleCards()">シャッフル</button>
<p>{{ number }}を選んでください.</p>
<div>
キーポイント
- methodsオプションでは変数名の前にthis.を付ける
- ボタンのイベント処理は v-onディレクティブ
繰り返し
配列cards
を宣言します.
要素は連想配列になっており,number
,front
,back
のキーに対する値を保持しています.
number
はカードの数字,front
はカードの面側の画像URL,back
はカードの裏側の画像URLです.
利用しているカードの画像は,パブリックドメインとしてKennyで提供されています.
この配列cards
を,data
オプションの変数として定義します(このように記述する方が視認性が良い).
// JavaScript
cards = [
{
"number": 1,
"front" : "https://assets.codepen.io/4660782/card_hearts_01.png",
"back" : "https://assets.codepen.io/4660782/card_back_00.png"
},
{
"number": 2,
"front" : "https://assets.codepen.io/4660782/card_hearts_02.png",
"back" : "https://assets.codepen.io/4660782/card_back_00.png"
},
{
"number": 3,
"front" : "https://assets.codepen.io/4660782/card_hearts_03.png",
"back" : "https://assets.codepen.io/4660782/card_back_00.png"
}
]
let app = new Vue({
el: "#app",
data: {
title: "数字当てゲーム",
description: "指定された数字と同じ数のトランプを選んでください.",
title_color: "color: green",
number: 1,
cards: cards,
},
methods: {
shuffleCards(){
// 1から3までの整数をランダムに設定
this.number = Math.floor(Math.random() * 3) + 1;
}
},
})
次に,v-for
ディレクティブを利用して,span
タグを繰り返し生成します.
ここでは,v-for="(card, index) in cards"
のように記述しています.
これは,配列の繰り返しを表す for of 文 と同様に,
配列cards
の要素card
と要素番号index
を,一つずつ取り出すことを表しています.
img
タグでは,v-bind
ディレクティブを利用して,src属性にカードの表側の画像URL(card.front
)を指定しています.
<!-- HTML -->
<div id="app">
<h1 v-bind:style="title_color">{{ title }}</h1>
<p>{{ description }}</p>
<button v-on:click="shuffleCards()">シャッフル</button>
<p>{{ number }}を選んでください.</p>
<div>
<!-- 3回繰り返して実行される -->
<span v-for="(card, index) in cards">
<img v-bind:src="card.front"></img>
</span>
</div>
<div>
shuffleCards()
を修正して,配列cards
の要素をシャッフル(ランダムに並び替える)するためのコードを追加します.
これにより,ボタンをクリックすると,カードの並び順が変化します.
// JavaScript
let app = new Vue({
el: "#app",
data: {
title: "数字当てゲーム",
description: "指定された数字と同じ数のトランプを選んでください.",
title_color: "color: green",
number: 1,
cards: cards,
},
methods: {
shuffleCards(){
this.number = Math.floor(Math.random() * 3) + 1;
this.cards.sort(()=> Math.random() - 0.5); // シャッフル
}
},
})
キーポイント
- 配列の繰り返しは v-forディレクティブ
- v-forディレクティブは「配列の要素」と「要素番号」を取り出す
条件分岐
data
プロパティにでselected
を定義します.
selected
の初値はfalse
に設定します.
また,shuffleCard()
をクリックしたときも,初期値のfalse
に設定します.
methods
プロパティで,selectedCard()
を定義し,selected
にtrue
を代入します.
選択されたカードの要素番号index
を引数として受け取ります.
// JavaScript
let app = new Vue({
el: "#app",
data: {
title: "数字当てゲーム",
description: "指定された数字と同じ数のトランプを選んでください.",
title_color: "color: green",
number: 1,
cards: cards,
selected: false, // 初期値はfalse
},
methods: {
shuffleCards(){
this.number = Math.floor(Math.random() * 3) + 1;
this.cards.sort(()=> Math.random() - 0.5); // シャッフル
this.selected = false; // falseを代入
},
selectCard(index){
this.selected = true; // trueを代入
}
},
})
条件に応じてHTMLタグの表示・非表示を制御するには,v-if
ディレクティブを利用します.
v-if
ディレクティブの条件がtrueのときに,指定されたHTMLが表示されます(ここではdiv
タグ).
また,v-if
ディレクティブの条件がfalseのときは,v-else
ディレクティブが実行されます.
ここでは,selected
がtrueのときにカードの表側を表示し,selected
がfalseのときにカードの裏側を表示します.
img
タグには,v-on
ディレクティブで,画像をクリックするとselectCard()
が呼び出されます.
このとき,選択されたカードの要素番号index
を引数として渡していることに注意してください.
<!-- HTML -->
<div id="app">
<h1 v-bind:style="title_color">{{ title }}</h1>
<p>{{ description }}</p>
<button v-on:click="shuffleCards()">シャッフル</button>
<p>{{ number }}を選んでください.</p>
<!-- カードの面側を表示 -->
<div v-if="selected == true">
<span v-for="(card, index) in cards">
<img v-bind:src="card.front"></img>
</span>
</div>
<!-- カードの裏側を表示 -->
<div v-else>
<span v-for="(card, index) in cards">
<img v-bind:src="card.back" v-on:click="selectCard(index)"></img>
</span>
</div>
<div>
ユーザが選択したカードの数字が大きいときは「あなたの勝ち!」,小さいときは「あなたの負け!」と表示します.
data
オプションに,message
を定義します.
selectedCard()
で,カードの大小を比較し,message
に代入する文字列を切り替えます.
// JavaScript
let app = new Vue({
el: "#app",
data: {
title: "数字当てゲーム",
description: "指定された数字と同じ数のトランプを選んでください.",
title_color: "color: green",
number: 1,
cards: cards,
selected: false,
message: ""
},
methods: {
shuffleCards(){
this.number = Math.floor(Math.random() * 3) + 1;
this.cards.sort(()=> Math.random() - 0.5); // シャッフル
this.selected = false;
this.message = "";
},
selectCard(index){
this.selected = true;
// カードの数字を比較
if(this.cards[index].number == this.number){
this.message = "あなたの勝ち!";
}
else{
this.message = "あなたの負け!";
}
}
},
})
次にHTMLの最後に,マスタッシュ構文でmessage
を表示させましょう.
これで,数字当てゲームは完成です.
<!-- HTML -->
<h2>{{ message }}</h2>
キーポイント
- 条件がtrueのときは v-ifディレクティブ
- 条件がfalseのときは v-elseディレクティブ
アプリの確認
See the Pen Chapter8 by Naoto Mukai (@nmukai) on CodePen.
課題
ユーザが勝ったときは赤色の文字で「あなたの勝ち!」,ユーザが負けたときは青色の文字で「あなたの負け!」と表示させてください.
課題を完成させたら,Penの ZIPファイル と リンク を提出してください. 提出方法は初回のWebアプリの開発を参考にしてください.