Vue.js①・データバインディング

Image from Gyazo

Vue.js

Vue.jsは,JavaScriptフレームワークの一つであり,フロントエンドの開発に用いられます. フレームワークとは,Webアプリの骨組みとしての役割を担い,データを同期させる データバインディング ,ウェブページの部品となる コンポーネント などの機能が提供されます. JavaScriptフレームワークには,Vue.js以外にも,ReactAngularなどがありますが,その中でもVue.jsは学習コストが低く,ページの一部分から大規模な開発まで手軽に利用できることが強みです. また,Vue.jsは日本での導入事例が比較的多く,日本語で書かれたドキュメントも豊富にあります(任天堂の公式サイトはVue.jsで開発).

CodePenの準備

CodePenにアクセスして,Penを作成し,タイトルを設定しましょう. Penのタイトルは「Chapter8」に設定しましょう.

https://codepen.io/

Image from Gyazo

ここでVue.jsのライブラリをペンに追加します. Settingsのウィンドウを開き,JS(JavaScript)のAdd External Scripts/Pensで,「Vue.js」を検索します. 検索結果の一覧から,バージョン2.6.11のVue.jsのCDN(Content Delivery Network)を追加します. CDNはライブラリなどに対するアクセスの集中を分散させる仕組みになっています.

Image from Gyazo

Vue.jsの基本構造

Vue.jsの基本構造として次のように記述します. HTMLでは,divタグにID属性(id="app")を設定します. JavaScriptでは,Vueクラスのインスタンスを作成します. 引数は連想配列で与えられ,eldatamethodsなどのオプションを指定します.

elでは,対応するdivタグのID属性を指定します. dataでは,次節で説明するデータバインディングのための変数を定義します. データバインディングとは,JavaScriptで宣言した変数を,HTMLで同期させる仕組みです. methodsでは,ボタンをクリックしたなどのイベントが発生したタイミングで実行する関数を定義します.

<!-- HTML -->
<div id="app">
<div>
// JavaScript
let app = new Vue({
  el: "#app", // 対象のID属性を指定
  data: {
    // 変数を定義
  },
  methods: {
    // 関数を定義
  },
})

データバインディング

データバインディングを利用して,ページのタイトルと説明文を記述しましょう. dataオプションに,titledescriptionを連想配列の形式で記述します. これらは,リアクティブデータと呼ばれ,データの更新がHTMLにも自動的に反映されます.

// JavaScript
let app = new Vue({
  el: "#app",
  data: {
    title: "数字当てゲーム",
    description: "指定された数字と同じ数のトランプを選んでください."
  },
  methods: {

  },
})

次に,タイトルを表すh1タグと,説明文を表すpタグをHTMLに追加します. このとき,dataオプションで定義したtitledescriptionを参照します. 参照するには マスタッシュ記法 に従って{{ title }}{{ description }}のように記述します. ちなみにマスタッシュ(Mustache)とは口髭のことです.

<!-- HTML -->
<div id="app">
  <h1>{{ title }}</h1>
  <p>{{ description }}</p>
<div>

Image from Gyazo

マスタッシュ記法は,属性のデータバインディングに用いることができません. この場合は,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>

Image from Gyazo

キーポイント

  • 要素のデータバインディングには マスタッシュ記法
  • 属性のデータバインディングには 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>

Image from Gyazo

キーポイント

  • methodsオプションでは変数名の前にthis.を付ける
  • ボタンのイベント処理は v-onディレクティブ

繰り返し

配列cardsを宣言します. 要素は連想配列になっており,numberfrontbackのキーに対する値を保持しています. 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>

Image from Gyazo

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); // シャッフル
    }
  },
})

Image from Gyazo

キーポイント

  • 配列の繰り返しは v-forディレクティブ
  • v-forディレクティブは「配列の要素」と「要素番号」を取り出す

条件分岐

dataプロパティにでselectedを定義します. selectedの初値はfalseに設定します. また,shuffleCard()をクリックしたときも,初期値のfalseに設定します. methodsプロパティで,selectedCard()を定義し,selectedtrueを代入します. 選択されたカードの要素番号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>

Image from Gyazo

ユーザが選択したカードの数字が大きいときは「あなたの勝ち!」,小さいときは「あなたの負け!」と表示します. 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>

Image from Gyazo

キーポイント

  • 条件がtrueのときは v-ifディレクティブ
  • 条件がfalseのときは v-elseディレクティブ

アプリの確認

See the Pen Chapter8 by Naoto Mukai (@nmukai) on CodePen.

課題

ユーザが勝ったときは赤色の文字で「あなたの勝ち!」,ユーザが負けたときは青色の文字で「あなたの負け!」と表示させてください.

Image from Gyazo

課題を完成させたら,Penの ZIPファイルリンク を提出してください. 提出方法は初回のWebアプリの開発を参考にしてください.

参考書籍

愛知県名古屋市にある椙山女学園大学 文化情報学部 向研究室の公式サイトです. 専門は情報科学であり,人工知能やデータベースなどの技術要素を指導しています. この公式サイトでは,授業で使用している教材を公開すると共に, ベールに包まれた女子大教員のミステリアスな日常を4コマ漫画でお伝えしていきます. サイトに関するご意見やご質問はFacebookまたはTwitterでお問い合わせください.