Vue.js | 文字またはリストの動的表示

Vue.jsの初期設定を行い、Vueを使ってテキストや配列などのデータを動的に表示してみよう。

まずVue.jsを使えるようにする

  • Vue 2.5.4

練習したい場合はCDNを利用するのが最も簡単である。公式サイトのはじめにで最初に紹介されている。

<script src="https://cdn.jsdelivr.net/npm/vue"></script>

このURLは常に最新バージョンを開発モードで読み込み、細かいエラーを表示してくれる。実運用ではminファイルを使用する。

ローカル環境以外にもhttps://jsfiddle.netを利用する方法も紹介されている。例を試したい場合におすすめである。また、このサイト内でもサンプルごとにコード実行があり、すぐに例を実行してみることができる。

Vue.jsはWebpackなどのビルド環境を必ず必要としないため、簡単に始められる。

Vueインスタンスを作る

まず最初にVueコンストラクタ関数を使ってルートインスタンスを作る。

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Vue Test</title>
</head>
<body>
  <div id="app">Hello {{ message }}</div>
  <script src="https://unpkg.com/vue/dist/vue.js"></script>
  <script>
  var vm = new Vue({
    el: '#app',
    data: {
      message: 'Vue.js!'
    }
  })
  </script>
</body>
</html>

要素がないという警告が出る場合は、bodyタグの下部などにJavaScriptを書き、DOMが読み込まれた後に実行されるようにする。変数にしておけば、次のようにコンソールや外部からアクセスできる。

vm.message = "test"

コンストラクタのオプションには、Vue.jsで使用するデータ、メソッド、マウントする要素などを指定できる。

  • el マウント要素の選択
  • data Vue.jsで扱うデータ
  • methods アプリケーションで使用するメソッド

いつnew Vueするのがよいか?

ところで、このVueコンストラクタ関数はどのタグに使うとよいのだろうか。初めて使うと分かりにくいだろう。

基本は1つのアプリケーション、たとえばブログならブログ全体にVueルートインスタンスを1つ作り、コンポーネント部品を増やしていく方式がよい。

部品を作るコンポーネントという機能があるため、メニューやフォームのように部品ごとにnew Vueすることはあまりないだろう。その場合、コンポーネントの利用法はほぼ必須なので、早めに学ぶとよい。

データはプロパティとして使う

何か操作するデータは、オプションのdataに定義して使う。

new Vue({
  el: '#app',
  data: {
    message: 'Vue.js!' // このデータを使う。
  }
})

dataに登録されたデータは、インスタンス生成時に自動的にリアクティブデータへ変換される。リアクティブデータになると、データ描画を同期するデータバインディングができるだけでなく、データの変化に応じて何らかの処理を行うこともできる。

Vueで使用するテンプレートを読み込むと、まず描画関数という通常のJavaScript関数に変換される。描画関数は登録されているデータの状態をもとに仮想DOMを構築し、仮想DOMの状態は非同期で実際のDOMに反映される。

簡単なテキスト表示

Vueに定義されたデータのプロパティとメソッドは、そのまま同じ名前でテンプレートから使用したり実行したりできる。

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Vue Test</title>
</head>
<body>
  <div id="app">
    <p>Hello {{ message }}</p>
  </div>
  <script src="https://unpkg.com/vue/dist/vue.js"></script>
  <script>
  var vm = new Vue({
    el: '#app',
    data: {
      message: 'Vue.js!'
    }
  })
  </script>
</body>
</html>

コード実行

データをテキストとして描画するには、データ名を{{ message }}のように二重波括弧で書いてテンプレートを作成する。これはMustacheという記法で、テキストコンテンツの一部としてデータをバインドする。両側のスペースは見やすくするためなので、なくてもよい。

上の例はルートにmessageというデータを持っているため、その値であるVue.js!というテキストが描画される。

メソッドでデータを使う場合は、this.messageのようにthisを指定する必要がある。

new Vue({
  el: '#app',
  data: {
    message: 'Vue.js!'
  },
  created: function() {
    alert(this.message)
  }
})

createdライフサイクルメソッドの1つである。

データをHTMLとして表示する

データバインディングでデータを表示するとき、XSS攻撃にならないようHTMLはエスケープ処理されたテキストとして表示される。信頼できるデータをHTMLとして表示するには、次のように書く。

<span v-html="message"></span>

XSSとは?

XSS脆弱性は簡単に発生し得るため、Webサイトで動的に任意のHTMLをレンダリングするのは非常に危険である。信頼できるコンテンツだけをHTML表示するべきである。外部から提供された入力値を表示する場合は注意が必要である。

テンプレート構文

要素の属性にデータを使う

属性の場合、テキストのように次のように書いても表示されない。

<p><a href="{{ url }}">{{ message }}</a></p> <!-- ここではURLは表示されない -->

属性にデータを使うには、v-bindディレクティブを使ってバインドする必要がある。

<p><a v-bind:href="url">{{ message }}</a></p>

また、v-bind:に省略できる。バインドする数が多い場合に簡潔になる。

<p><a :href="url">{{ message }}</a></p>

最初は慣れていないと読みにくいかもしれないので、v-bindを書いておき、慣れてから省略するのがよいかもしれない。

一部をVueでレンダリングしない

特定の要素以下をVueでレンダリングする必要がない場合もあるだろう。v-preディレクティブを使うと通常のHTMLとして認識されるため、動的コンテンツを含まない場合に指定しておくと性能が上がることもある。v-onceディレクティブは最初だけレンダリングし、その後は静的コンテンツとして扱われる。後からmessageが変更されても要素は更新されない。

展開されないためMustacheの状態で表示される。

<p><a v-bind:href="url" v-pre>Hello {{ message }}</a></p>

最初にmessageを表示した後、リアクティブを解除する。

<p><a v-bind:href="url" v-once>Hello {{ message }}</a></p>

コード実行

静的HTML文書や、表示した後は監視する必要がない場合に性能改善として活用できそうである。

変更をリアルタイムで反映する

少し順序が早いが、このようなフレームワークのサンプルでよく見かける、変更をリアルタイムで反映できるフォームを作ってみよう。もちろんjQueryや素のJavaScriptでもできるが、管理するのはかなり面倒である。入力フォームとデータの接続にはv-modelディレクティブを使う。

<div id="app">
  <input v-model="message">
  <p>{{ message }}</p>
</div>

dataオプションにmessageというデータを作っておく。

new Vue({
  el: '#app',
  data: {
    message: 'こんにちは。'
  }
})

コード実行

チェックボックスやセレクトメニューの場合はどうなるのか知りたいかもしれないが、それはもう少し基本を学んでから詳しく説明していく。

v-で始まるディレクティブ

これまでにもv-bindv-htmlなどが出てきたが、今後Vue.js独自の属性であるv-で始まるものがいろいろ出てくる。これはVue.jsで特別な役割を持つ属性で、ディレクティブと呼ばれる。そしてv-で始まる属性値は、テキストではなくJavaScript式であることがポイントである。他にもVue.js独自の属性はあるが、v-で始まらない場合、基本的に値は単なる文字列である。ただしslot-scopeは除く。v-preなどのように値がないものは特に深く考えなくてよい。

リストをループで表示する

少し本格的なアプリケーションを作るなら、当然単純なテキストだけではないため、さまざまな形式のデータを定義して表示してみよう。

リスト表示

次のようにlistという簡単な配列データを表示する。

new Vue({
  el: '#app',
  data: {
    list: ['リンゴ', 'バナナ', 'イチゴ']
  }
})

リストを表示するにはv-forというディレクティブを使う。

<div id="app4">
  <ul>
    <li v-for="val in list">{{ val }}</li>
  </ul>
</div>

v-forディレクティブの値は、通常JavaScriptのループで使うfor..in文に似ているが、実際の動作はfor..ofに近い。

コード実行

オブジェクト表示

次のようなオブジェクトデータをループで表示してみよう。

new Vue({
  el: '#app',
  data: {
    list: {
      a: 'ハンバーガー',
      b: 'プルコギ',
      c: 'パスタ'
    }
  }
})

括弧を使うと、オブジェクトの場合は値とキーとインデックス、配列の場合は値とインデックスを任意で受け取ることができる。

<div id="app">
  <ul>
    <li v-for="(val, key) in list">(Key:{{ key }}) {{ val }}</li>
  </ul>
</div>

オブジェクトの処理順序はJSONの特性上保証されない。

コード実行

オブジェクトのリストを表示する

次に、ネストされた少し複雑なオブジェクトのリストをループで表示してみよう。

new Vue({
  el: '#app',
  data: {
    list: [
      { name: 'トマト', price: 100 },
      { name: 'レタス', price: 200 },
      { name: 'きゅうり', price: 300 }
    ]
  }
})

配列をループするのと同じなので、必要なければインデックスは取得しなくてもよい。

[コード実行](/code/?id=29)

コード実行

v-bind:keyでIDのようなユニークキーを指定しておくことが推奨されている。このリストが更新されるときのレンダリング最適化のためであり、後で操作したい場合は付けておくとよい。今後はキーの指定が必須になるかもしれない。

まずはさまざまな種類のデータを表示する方法を学んだ。次の章では、表示データをVueを使って更新してみよう。