Vue.js で文字やリストを動的に表示する

最終更新日
2018.03.05

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 タグの一番下など DOM が読み込まれたあとに実行するようにします。 変数化しておくことで、次のようにコンソールまたは外部からアクセスできるようになります。

> vm.message = "test"

コンストラクタのオプションには、Vue.js で使用するデータ、メソッド、マウント(配置)する要素などが指定できます。 いくつか紹介。

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

いつ new Vue すればいいの?

ところでこの Vue コンストラクタ関数はどのタグで使えば良いのでしょう?これ初めてだと意外と分からない。 Vue を始めたころ Slack で質問してみたところ丁寧に教えてもらえました。

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

と言うことです。部品を作るコンポーネントという機能があるので、メニューやフォームというように部品毎に new Vue するわけではないようです。 となるとコンポーネントの扱い方はほぼ必須なので早めに覚えた方がよさそう。

データはプロパティから使う

何かしら操作したいデータはオプションの data に定義して使用します。

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

deta に登録されたデータはインスタンス作成時に自動でリアクティブデータに変換されます。 リアクティブデータにすることで、データと描画を同期させるデータバインディングをしたり、それだけでなくデータの変化に応じて何か処理をさせることもできるようになります。

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 }} このような2つの大カッコで囲み、テンプレートに記述します。 これは Mustache(マスタッシュ)と呼ばれる記法で、テキストコンテンツの一部としてデータをバインドします。 両端のスペースは見やすくするためだけなのであってもなくてもOK。

今はルートに message というデータを持っているので、その値の「Vue.js!」というテキストが描画されます。

メソッドからデータを使用する場合は this.message というように this を付ける必要があります。

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

createdライフサイクルメソッドのひとつです。

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

データバインディングしてデータを描画したとき XSS 対策で HTML はエスケープされテキストとして表示されます。 信頼出来るデータを HTML として表示したい場合は、次のように記述する必要があります。

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

XSS 脆弱性を容易に引き起こすので、ウェブサイトで動的に任意のHTMLを描画することは、非常に危険です。信頼できるコンテンツにだけ HTML 展開を利用してください。ユーザーから提供されたコンテンツに対しては決して使用してはいけません。

テンプレート構文

プロフィールやコメントなどユーザーが入力したデータをそのまま v-html で展開したり、勿論テンプレートに使用してはいけない。 基本的な JavaScript の XSS 対策と一緒ですね。

要素の属性にデータを使用する

属性の場合、テキストと同じ感覚で次のように書いても展開されません。

<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 が変わっても要素は更新されません。

一切展開されないのでマスタッシュのまま表示
<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 やプレーンでも出来る事なんですけどこういうのを管理するのはとても大変。 入力フォームとデータの紐付けには v-model ディレクティブを使用します。

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

dataオプションのほうに message というデータを作っておきます。

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

テンションあがる!勉強も頑張れそうです(๑'ᴗ'๑) チェックボックスやセレクトメニューの場合どうなるんだろうとか色々知りたいこともありますが、このへんはもう少し基本を学んでから続きをやっていきましょう。

v-から始まるディレクティブ

ここまでにも v-bindv-html など出てきましたが、これから Vue.js の独自の属性 v-なんちゃら というものが色々出てきます。 これは Vue.js での特別な役割を持った属性で ディレクティブ と呼ばれます。 そして、v- から始まる属性の値は、テキストではなく JavaScriptの式 というのがポイントです。 他にも Vue.js 独自の属性はありますが、 v- から始まっていなければ基本的に値はただの文字列です。(slot-scopeを除く) v-pre など値が無いものは特に考えなくてもOK。

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

少し凝ったアプリケーションを作るなら当然単純なテキストばかりではないので、色々な形式のデータを定義してそれを描画してみましょう。

リストの表示

次のような list という単純な配列データを表示させます。

new Vue({
  el: '#app4',
  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: '#app5',
  data: {
    list: {
      a: 'ハンバーグ',
      b: '焼肉',
      c: 'パスタ'
    }
  }
})

括弧を使うとオブジェクトは値とキーとインデックス、配列の場合は値とインデックスを任意に受け取れます。

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

ブラウザによってはオブジェクトの処理順は保証されないようです。

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

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

new Vue({
  el: '#app6',
  data: {
    list: [
      { name: 'とまと', price: 100 },
      { name: 'れたす', price: 200 },
      { name: 'きゅうり', price: 300 }
    ]
  }
})

配列をループするのと同じなので、不要ならインデックスは取得しなくてもOK。

<div id="app6">
  <ul>
    <li v-for="(val, idx) in list" v-bind:key="val.name">
      (No:{{ idx }}) {{ val.name }} {{ val.price }}円
    </li>
  </ul>
</div>

v-bind:key で ID 等のユニークなキーを指定しておくのが推奨されています。 もしこのリストが更新されたとき描画の最適化を行うようなので、後から操作したいなら付けておくといいです。 今後キーの指定が必須になることもあります。

まずは色々な種類のデータの描画方法を覚えました! 次回は描画したデータを Vue を使って更新してみたいと思います。