簡単な HTML のデモを作るのに Vue.js を重宝している。「この値が変わるとこっちの値も変わる」ような連動する画面要素を作るのに便利。久しぶりに触ると完全に忘れていて困ったので Introduction — Vue.js のメモを残す。日本語訳もあり助かる。
宣言的にきれいに書くコツ
- v-on: イベントハンドラは使わない。
- v-model と computed を駆使する。
基本
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
を含める。
<div id="app">
{{ message }}
</div>
<script>
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
</script>
- 新しい
Vue
オブジェクトを作り、描画したい HTML 要素の ID をel
で指定する。この例では Vue オブジェクトを app と名付ける。 -
data
の中に、HTML から参照するデータ変数の初期値を定義する。-
data
内に定義したデータは不思議な事に app.message のようにして参照出来るようになる。
-
- HTML タグのテキスト要素内に
{{}}
でくくってdata
で定義した名前を書くと、HTML の中に描画される。
v-bind: HTML 属性の操作
HTML テキスト要素ではなく、HTML 属性を動的に変更したい場合は v-bind:属性名 という属性を使う。以下の例では app.title が使われる。
<div v-bind:title="title">Please hover</div>
v-if, v-for: 条件表示とループ
条件による表示非表示の切り替えには v-if
, ループには v-for
を使う。
<div>Condition:
<span v-if="seen">Now you see me</span>
</div>
<ul>
<li v-for="(place, index) in places" v-bind:key="place.id">
{{index}}: {{ place.name }}
</li>
</ul>
<script>
var app = new Vue({
el: '#app',
data: {
seen: true,
places: [
{ id: 'tower1', name: '通天閣' },
{ id: 'tower2', name: 'スカイツリー' },
],
}
})
-
v-for
の中で(place, index) in places
のようにすると、リストの要素とインデックスを取得出来る。- インデックスが不要な時は
place in places
で良い。
- インデックスが不要な時は
-
v-bind:key
で要素に一意の値を指定すると、再描画の最適化に使われる。- 再描画時 key の変更が無い要素を使い回す。
- key の指定が無ければ、要素はそのまま内容を書き換える。(参照: key)
v-on: イベント
v-on:イベント名 属性でイベントハンドラを設定する。イベントハンドラ内で data 内の変数を変更すると画面は自動的に再描画される。
<div v-on:click="onClick">Event: {{ time }}</div>
<script>
var app = new Vue({
el: '#app',
data: {
time: 'Click me',
},
methods: {
onClick: function(e) {
this.time = new Date();
}
},
})
v-model: フォーム入力
v-model で HTML フォームと Vue 変数を結びつける。これを React.js でやると果てしなく面倒臭い。フォームに入力された内容を変数にセットするだけで一見単純に見えるが、value, checked, selected 等フォームの違いによる属性の差を吸収してくれる。
<div>Template: {{ message }}</div>
<input v-model="message"/>
<script>
var app = new Vue({
el: '#app',
data: {
message: 'Dynamic message',
},
})
</script>
詳しくは Form Input Bindings
省略記法
検索し辛い省略記法 Shorthands
- HTML 属性を操作する v-bind は省略出来る。
- 省略前:
<a v-bind:href="url"> ... </a>
- 省略後:
<a :href="url"> ... </a>
- 省略前:
- @ はイベントハンドラの v-on の意味
- 省略前:
<a v-on:click="doSomething"> ... </a>
- 省略後:
<a @click="doSomething"> ... </a>
- 省略前:
computed: 自動計算 Computed Properties
ここが Vue.js の一番おもしろい所。まるで Excel のように自動計算出来ます。以下の例では、角度の数値を度数法とラジアンを変換します。度数法を入れるとラジアンが変化し、ラジアンを入れると度数法が変化します。
<div>Degree: <input v-model="degree"/></div>
<div>Radian: <input v-model="radian"/></div>
<script>
var app = new Vue({
el: '#app',
data: {
degree: 90,
},
computed: {
radian: {
get: function() {
return Math.PI * 2 * this.degree / 360
},
set: function(newValue) {
this.degree = 360 * newValue / (Math.PI * 2) ;
}
}
}
})
</script>
この例では、プロパティの読み書き両方に対応するために setter 構文 を使っているが、読みだけで良い場合は普通の関数でもよい。
Degree: 90
Radian: 1.5707963267948966
watch: データの更新を受け取る Watchers
あるデータの変更によって表示を変えたい時はだいたい computed を使えば間に合う。ただ、ネットワークアクセス等で非同期に変更した場合は watch の方が良いらしい(computed 内で非同期処理をするとどうなるか調査中)
<select v-model="yesno">
<option value="yes">Yes</option>
<option value="no">No</option>
</select>
<img v-bind:src="yesnoImg"/>
<script>
var app = new Vue({
el: '#app',
data: {
yesno: "yes",
yesnoImg: "",
},
created: function() {
this.yesno = "no";
},
watch: {
yesno: async function(newValue, oldValue) {
this.yesnoImg = "";
const response = await fetch(`https://yesno.wtf/api?force=${this.yesno}`);
const json = await response.json();
this.yesnoImg = json.image;
}
},
})
</script>
この例では、yes または no を選択するとそれに応じた画像を出力する。また created
を使って起動時にも no の画像を出すようにする。
created などのすべての Vue オブジェクト作成時のプロパティは API — Vue.js に記載がある。
コードサンプル: https://gist.github.com/propella/97af35302e9674475f0855de553c44ad