Vue.js の基本 (5)

ループは、どのようなプログラミング言語でもテンプレートエンジンでも備えられていますが、もう1つ備えられているものがあります。分岐です。

Vue にも分岐を行うための仕組みがあります。それが v-if 属性です。

非常にシンプルです。v-if 属性に指定した値が true であれば、その要素がレンダリングされます。false であればレンダリングされません。

ここで注目したいのは、表示/非表示を切り替える処理を実装しているわけではなく、データによってリアクティブにそれが行われているということです。

上の例ではチェックボックスにチェックすることによってその下に div 要素が現れますが、チェックボックスの値を取得する処理を書くこともなく、 チェックボックスの値によって表示/非表示を切り替える処理を書くこともなく、この動きを実現しています。


if があるなら else も else-if もあります。使い方は... イメージ通りだと思います。


v-if に似たものとして、v-show という属性もあります。

動きは最初の例と同じように見えますが、見えないところに違いがあります。
v-if はその要素の存在そのもののありなしを制御するのに対し、v-show は、その要素を CSS で見えなくしているだけです。




Vue.js の基本 (4)

どのようなプログラミング言語でも、テンプレートエンジンでも、ループを行うための仕組みがあります。

Vue でそれを行うのは、v-for 属性です。なお Vue 独自の属性には、すべて v- というプレフィクスがついています。

データは list という配列で、要素は 'a' 'b' 'c' という3つの文字列です。
HTML では、v-for タグを使用して、ループを行っています。v-for では、それを指定したタグが、指定した内容に基づいて複数回レンダリングされます。

for (...) {
  <span>...</span>
}

的な書き方ではありません。

v-for に指定するのは、配列*1の指定と、その要素にアクセスする変数名の指定です。
{要素の変数名} in {配列} となります。 指定した list は 'a' 'b' 'c' という3つの文字列だったので、item in list の item には、 'a' 'b' 'c' が順番に入ることになります。

<span v-for="(item, index) in list">{{ index }} {{ item }}</span>

このようにすることで、インデックスを取得することもできます。foreach 系言語構文でインデックスを扱うには自前でインクリメントしないといけない場合もありますので、これは便利です。

そして、v-for に指定する配列の要素は、オブジェクトでも大丈夫です。

実際のシステムでは、オブジェクト構造、リスト構造がネストし、それらをループしながらデータを入力させたり表示させたりすることは常です。
PHP であれば、どんな name 属性にするか考慮が必要になります。name 属性自体はフラットなため、name="list[0]['name']" のような書き方をしなければなりません。 これではネストが深くなったときに苦しくなってくるのは明らかです。

これに対し Vue では、上記のコードのように v-model="item.name" というとても直感的な書き方ができています。




*1:オブジェクトも指定できます。その場合はオブジェクトのプロパティをループすることになります。

Vue.js の基本 (3)

前回、テキストボックス、ラジオボタン、セレクトボックスについて、UI 要素と JavaScript のデータがひもづく-バインディングされる様を確認しました。

UI 要素には他にも、複数のデータとひもづくものがあります。チェックボックス、複数選択セレクトボックスなどです。

古典的な仕組みでは、name 属性に同じ値を持たせた複数の input を用意してサブミットすることで、サーバサイドではそれらを配列として扱うことが多いかと思います。例えばこうです。

<input type="checkbox" name="gender[]" value="female" />
<input type="checkbox" name="gender[]" value="male" />
<input type="checkbox" name="gender[]" value="other" />

こうすると、PHP では

$selected = $_POST['gender']; // $selected には選択したものが配列でセットされる

となります。

ちなみに、ここからHTTPレスポンスを返すとき、チェック状態を復元する必要があることが多いですが、PHP のみの機能では、それを実現するのは結構面倒です。 データにしたがって適切に checked 属性をつけた HTML コードを生成しなければならないからです。
これはこのシチュエーションに限った話ではなく、最初に表示するとき登録されているデータにもとづいてチェック状態をセットするとか、セレクトボックスの選択状態、テキストボックスの初期値など、データにもとづいて UI 要素を表示するためには必要なことになります。

これが Vue.js では、このようになります。

JavaScript の方は、data に genders という配列があります。

HTML では、それぞれのチェックボックスに v-model 属性を使用して genders がバインドされています。

span は、genders の中身を表示する部分です。詳細は割愛しますが、genders の中身をループして表示しています。

これを動かしてみると、チェックボックスの状態によって、genders の内容がリアクティブに変化していることがわかります。チェックされたチェックボックスvalue 値が、バインドされた genders の配列の要素となっています。

これにより、表示する際のチェックボックスの復元も簡単に実現できます。単に、チェックをつけたい値が配列に設定されていればよいのです。
最初に male をチェック状態にしたいならば、

data: {
  genders: ['male']
}

のようにすればよいだけです。




Vue.js の基本 (2)

Vue.js を使用する場合の入力要素とのつなぎこみを見ていきたいと思います。

表示する場合は、ビューモデルデータを {{ }} という記法を用いて表示させることができました。
ユーザが入力した内容をビューモデルデータに反映させるためには、v-model という特殊な属性を使用します。

百聞は一見にしかず、コードを見てみます。

JavaScript の方は、data に text. pulldown, radio という3つの項目があるだけです。何も処理はないため今回は methods はありません。

HTML を見てみると、<input type="text" v-model="text" /> というコードがあります。
この v-model="text" が、「input に入力された内容は data の text に入れるよ」という意味になります。
data の text の値が変更されれば、テキストボックスの内容も変更されます。テキストボックスからデータ、データからテキストボックスへ、双方向にひもづけされる*1ということです。

テキストボックス以外でも同じようになります。上記の例ではプルダウンとラジオボタンですが、テキストボックスと同じように data とひもづけられていることが確認できるかと思います。

プルダウンやラジオボタンでは、data の方の値を設定しておくことによって、初期値を設定することができます。
例えば radio: '' となっているところを radio: 'b' とすれば、表示された段階で b のラジオボタンが選択されている状態になります。




*1:Vue ではこれをバインディングといいます。この場合は双方向バインディングになります。

Vue.js の基本

Vue.js は、公式ページにおいて

Vue はユーザーインターフェイスを構築するためのプログレッシブフレームワークです。

と説明されている通り、ユーザインタフェース - HTML(DOM) とその上で制御することに特化したフレームワークです。
提供される機能がユーザインタフェース周りに限定されているため、非常に「軽い」ところが気に入っています。

Vue の中心となるのが Vue オブジェクトです。
これは、ビュー(view)のデータをモデル化したオブジェクトです。オブジェクトですから、データと振る舞いを持ちます。

これは、「増やす」ボタンをクリックすると、隣にある数字をインクリメントするアプリケーションです。

HTML は非常にシンプルで、id 属性が "app" の div の中に、button が1つあり、その隣に {{ count }} という見慣れない記述があります。

JavaScript のコードでは、Vue オブジェクトを生成しています。このとき、オプション el に、ひもづける要素を指定します。el:'#app' なので、HTML で記述した div タグを指していることになります。

他にも data と methods という2つのオプションがあります。この2つのオプションこそが、オブジェクトのデータと振る舞いです。

Vue では、いくつか特殊な記法を用いることになります。

  • @~ イベントをハンドリングします。@click="..." と書けば、クリックしたときの処理(JavaScript)を記述することができます。また、オブジェクトのメソッドを指定することができます。@click="inc" であれば、クリックされたときに inc メソッドを呼び出すということになります。

  • {{ ~ }} オブジェクトのデータを表示します。{{ count }} であれば、オブジェクトの count の値が表示されます。

  • v-model, v-for などの特殊な属性 別記事にて説明

inc メソッドがいかにもオブジェクト的な処理になっていることがおわかりいただけるかと思います。inc メソッド内では、その count をどこに表示するかとか、何がきっかけに呼ばれているのかだとかを意識せず、単に自分のデータである count をインクリメントしています。

ポイント:

  • Vue は Vue オブジェクトが中心となり、それは HTML の任意の要素と結びつく

  • データを表示するときは {{ ~ }} を使う

  • イベントをハンドリングするときは @~ を使う




Vue.js でリアクティブな動作を見る (2)

こちらが前回の例

ですが1つ書き忘れていたことがありました。

ラベルの表示内容はオブジェクト { name: '' } の name の変化に反応して変わるわけですが、
このオブジェクトのプロパティ name の値もまた、input タグの入力内容に反応して自動的に内容が書き換わります。

つまり、
input タグに入力する
 → それに反応してオブジェクトのnameが書き換わる
  → それに反応してラベルの表示内容が書き換わる
というわけです。
Vue.js では、この動作についての処理を書く必要はありません。処理を書くのではなく、v-model 属性や {{ name }} のような Vue.js 固有の書き方(しかしトランスパイラ等を必要としません!)でこの動作を宣言的に定義することになります。

これまでは、
input タグに入力する
・その input タグの内容を $('#name').val() などを使用して取得する
・取得した値を $('#name-label').text などを使用してセットする
という JavaScript の処理を書かなければなりませんでした。

この極めてシンプルな例では、Vue.js を使用する場合としない場合とであまり差異を感じられないかもしれません。しかし、Web アプリケーションのフロント部分の基本的な機能構成は、 ・サーバサイドデータを画面要素に表示 ・エンドユーザの画面要素への入力 ・エンドユーザの入力内容のサーバへの送信 からなり、通常の Web アプリケーションでは画面要素が1つ2つなどということはありませんから、画面要素とモデルデータとのつなぎ込みは膨大な量になります。

Vue.js を使用することで、その画面要素とモデルデータをつなぎ込む処理から解放されることになります。
もちろん、「どの要素がどのデータに対応する」ということは宣言的に書かなければなりません。しかしそれでも、コードの見通しは非常に良くなると感じます。




Vue.js でリアクティブな動作を見る

テキストボックスの内容を、別のラベルの中に転記したいとします。
jQuery を使った典型的なコードでは、以下のようになります。


これは、

  • テキストボックスへの入力が発生したら
  • テキストボックスの要素を取得してそのvalue値を取得し
  • ラベルの要素を取得してその内容にセット

しています。当たり前ですが、自分でテキストボックスの内容をラベルに移しているわけです。

一方、Vue.js を使用すると、以下のようになります。


こちらのバージョンでは、自分でテキストボックスの値を取得してラベルに設定する、ということを行っていません。
Vue オブジェクトのコンストラクタに渡しているオブジェクト { name:'' } の name の値が変化することにより、それに反応して(reactive)ラベルの内容が書き換わっています。

これまでは、

  • DOM <-> データ のやり取り
  • データ <-> サーバサイドのやり取り

を自分で書かなければいなかったわけですが、Vue.js を導入することにより、データの取り扱いに注力することができるようになります。