Vue.js について簡単にまとめてみた

Vue.js とは

Vue.js はそれ自体では、ビューのみを扱うライブラリであり、厳密にはフレームワークではない。よって、Web アプリケーションを実現するためには、ルーティングのような UI 以外の機能については、追加のライブラリを利用する必要がある。

それらをサポートするために、Vue.js では本体以外にそうしたプラグイン、ライブラリ、ツールを提供している。

Vue.js の重要な技術

Vue.js にはアプリのパフォーマンスや開発利便性を高めるために3つの重要技術がある。

コンポーネントシステム

Vue.js は HTML ライクなコンポーネントを単一ファイルに書くことができ、この仕組みのことを単一ファイルコンポーネントと呼ぶ。

コンポーネント単位で、機能や関心ごとで切り出せることが単一ファイルコンポーネントの旨味となっている。

リアクティブシステム

状態変化を Vue.js が監視し、自動的に DOM 側に反映できる仕組み。変更検知だけでなく、値の更新などを開発者が意識することなく処理してくれる。

レンダリングシステム

Vue.js では仮想 DOM(Virtual-DOM) による DOM のレンダリングを提供している。仮想 DOM は DOM 操作を簡略化、高速化するための技術で、アプリ開発の利便性を向上している。

Vue.js の基本操作

Vue インスタンスのマウント

Vue.js は Vue インスタンスを生成し、DOM 要素にマウントするところから始まる。マウントは、既存の DOM 要素を Vue.js が生成する DOM 要素で置き換えることをいう。

オプションオブジェクトの el プロパティで指定した DOM 要素がマウント対象。

データの定義

UI の状態となるデータオブジェクトを指定する。data プロパティに与えた値は、リアクティブシステムに乗り、data プロパティの値が変更されるたびに、Vue.js がそれを検知して、表示などを切り替える。

image.png

データの変更検知

Vue.js はデータの代入と参照は監視されている。次のようなコードを用意して、そのことを確認する。

<!DOCTYPE html>
<title>初めてのVue.js</title>
<script src="https://unpkg.com/vue@2.5.17"></script>

<div id="app">
  <p>{{item}}</p>
</div>

<script>
  let vm = new Vue({
    el: "#app",
    data: { item: "hoge" },
  });
</script>

そして、Vue インスタンスの変数をデベロッパーツールで更新すると、ブラウザの再読み込みなしで値が更新される。

Image from Gyazo

上記のように、データの変更に応じてビューを更新する仕組みのことをデータバインディングという。

テンプレート構文

テンプレートでは、Vue インスタンスのデータとDOMツリーの関係を宣言的に定義する*1

テンプレート構文には重要な2つの概念がある。

  • Mustache 記法によるデータ展開 ({{}}を用いた記法)
  • ディレクティブによる HTML 要素の拡張(HTML の属性を用いた独自拡張。v-で始まる属性)

フィルタ

フィルタは、0.5 を "50%" のパーセンテージテキストにしたり、Date オブジェクトを YYYY/mm/dd 形式にしたりと、汎用的なテキストフォーマット処理を適応する仕組みのこという。

フィルタを定義するには、Vue のコンストラクタへのオプション filters で引数を1つとる関数として定義し、テンプレート側では {{ <引数>|<フィルタ名> }} で適応する。

image.png

フィルタは連結でき、 {{ <引数> | <フィルタ1> | <フィルタ2>}} と書けば左側のフィルタの結果が次のフィルタに渡される。イメージ的には Unix のシェルのパイプのような感じ👀

算出プロパティ

算出プロパティは、あるデータから派生するデータをプロパティとして公開する仕組みのこと。算出プロパティを用いるときは、 Vue のコンストラクタへのオプション computed を用いる。

算出プロパティの活躍どころは、Mustache({{}}) 展開で複雑な処理を記述したいシーン。Mustache 展開の JavaScript 式は単一の式しか記述できない制約があるため、無理に書くとテンプレートの保守が大変になってしまう。テンプレートと実装は分けておくと開発しやすいということ。

image.png

ディレクティブ

ディレクティブは v- から始まる Vue.js 特有の属性で、標準 HTML に対して独自の属性を追加することで属性値の式の変化に応じた DOM 操作を行う。

ディレクティブによって、属性の設定のほかに、テンプレート中の要素の表示を条件ごとに切り替えたり、繰り返しのレンダリングが可能になる。

条件付きレンダリング(v-if/v-show)

条件付きレンダリングはテンプレート中の要素の表示/非表示を切り替えたい時に使う。v-ifv-show の違いは、v-show による要素は常に DOM に維持され、表示/非表示の切り替えをCSSの書き換えによって実現している点にある。

どちらを使うかについては、v-showCSS の切り替えというシンプルな方法なため、v-if に比べて切り替えコストが低いらしい。よって、切り替え頻度が高い場合は v-show, 条件が実行時に変わらないような場合には v-if という使い分けがされている。

クラスとスタイルのバインディング

フォーム入力で不正値の時にはフォームを赤くするなど、特定の条件が成立するときの UI を変えたいという時に使えるのが v-bind ディレクティブ。

次の記法で書き、オブジェクトや配列が属性値に指定されたら、要素やプロパティを結合して、最終的に文字列として評価する。

v-bind:<属性名>="データを展開した属性値"  // 基本形
v-bind:class="オブジェクト、配列"       // class を指定
v-bind:style="オブジェクト、配列"       // style を指定
  • クラスのバインディング

    v-bind:class は属性値にオブジェクトを指定した場合、あたいが真のプロパティを class 属性値として設定する。次のような場合、classfoo が設定される:

  <p v-bind:class="{hoge: false, foo: true}">

アプリケーションの規模が大きくなり、属性値のオブジェクトのプロパティの数や値の式が複雑になってきた時は、オブジェクトをテンプレートに直接書くのではなく、算出プロパティとして Vue インスタンスで設定すると、コードの管理がしやすくなる。

  • スタイルのバインディング

    v-bind:style は、属性値のオブジェクトのプロパティが style のプロパティと対応し、インラインスタイル形式で反映される。次の例では <p style="color: red:">hoge</p>になる:

  <p v-bind:style="{color: 'red'}">hoge</p>

また、v-bind ディレクティブは最頻のディレクティブのため簡潔記法(:<属性名>)で記述できる。

image.png

リストレンダリングv-for

配列やオブジェクトのデータをリストレンダリングしたい時に用いるのが v-for ディレクティブ。

次の構文によって記述する:

v-for="<要素> in <配列>"

v-for では、Vue.js のパフォーマンス等の理由から、v-bind:key=● で生成時に一意なキーを各要素に与える。下記例は、一意ではないキーを与えているが、データベースなどのデータを用いる場合はレコードの ID を用いるなどをする。

image.png

イベントハンドリング(v-on)

アプリケーションを操作して Vue インスタンスを操作する時に用いるのが、v-on ディレクティブ。v-on はイベント発生時に属性値の式を実行する。 次の構文によって記述する:

v-on:イベント名="式として実行したい属性値"
@イベント名="式として実行したい属性値" // 省略記法

Vue.js が提供している DOM イベントのオブジェクト参照 $event と、v-on:change - v-bind:value を使うことで、下記のように入力を動的に反映するようにできる。

Image from Gyazo

フォーム入力バインディング(v-model)

イベントハンドリングの例のように、UI からの入力を v-on:change - v-bind:value を組み合わせることで利用できるようになるが、フォームが複数あると管理が大変になる。

そこで v-model が役立つ。v-model ディレクティブは双方向データバインディングを実現するディレクティブ。

ビュー(DOM) に変更があると、その値を Vue インスタンスのデータとして更新し、Vue インスタンスのデータに変更があるとビューを再レンダリングする。

// `v-on:change` - `v-bind:value`で実現する場合
<input type="number" @input="item.quantity = $event.target.value" 
       v-bind:value="item.quantity" min="0" />

// `v-model` で実現する場合
<input type="number" v-model="item.quantity" min="0" />

メソッドとは

メソッドは、 Vue インスタンスのメソッドとして機能し、 Vue インスタンスのコンストラクタオプションの methods プロパティで定義する:

methods: {
  メソッド名: function(){
    // 処理
  }
}

methods はデータ変更やサーバに HTTP リクエスト送る際に使用する。

メソッドにより、ToDo アプリのメモ追加が実装できそうだったので実装してみました💪

Image from Gyazo

参考

*1:データが決まれば、ビューの内容が決定される