Vue.js
基本
セットアップ
<div id="app" />
var app = new Vue({
el: '#app',
});
Interpolation (展開)
<span>{{message}}</span>
// index.js
var app = new Vue({
data: {
message: 'hello!',
},
});
bind
属性にデータをバインドする。バインドしないと、ただのテキストとして評価される。
<a v-bind:href="someUrl" /> <a :href="someUrl" />
new Vue({
data: {
someUrl: 'http://someghing.com/',
},
});
if
<span v-if="rock">you rock!</span>
new Vue({
data: {
rock: true,
},
});
for
<li v-for="todo in todos">{{ todo.text }}</li>
new Vue({
data: {
todos: [
{ text: 'Learn JavaScript' },
{ text: 'Learn Vue' },
{ text: 'Build something' },
],
},
});
on
イベントリスナを設定する。
{{message}}
<button v-on:click="onButtonClick" />
<button @click="onButtonClick" />
new Vue({
data: {
message: 'Hello',
},
methods: {
onButtonClick() {
this.message = 'Hello Again!';
},
},
});
model
two-way binding を設定する。
<input v-model="name" />
new Vue({
data: {
name: 'john',
},
});
components
<todo-item v-for="item in groceryList" v-bind:todo="item" />
Vue.component('todo-item', {
props: ['todo'],
template: '<li>{{ todo.text }}</li>',
});
new Vue({
data: {
groceryList: [
{ id: 0, text: 'Vegetables' },
{ id: 1, text: 'Cheese' },
{ id: 2, text: 'Whatever' },
],
},
});
Vue Instance
インスタンスの作成
const vm = new Vue(options); // root Vue instance
Vue.component('some-component', options); // other Vue instances
data
- data プロパティに渡したオブジェクトは、Vue の Reactivity System に組み込まれる。
- インスタンスからの変更、元データの変更は、双方向に反映される。
- data の変更は自動的に View に反映される。
- data に後からプロパティを追加することはできない。
var data = { a: 1 };
var vm = new Vue({
data: data,
});
vm.a === data.a; // => true
vm.a = 2;
data.a; // => 2
data.a = 3;
vm.a; // => 3
規定のプロパティ・メソッド
インスタンスには、名前が$
で始まる、規定のプロパティとメソッドがある。
vm.$data === data; // => true
vm.$el === document.getElementById('example'); // => true
vm.$watch('a', function (newValue, oldValue) {
// This callback will be called when `vm.a` changes
});
Lifecycle Hooks
- いくつかのライフサイクルメソッドがある
- ライフサイクルメソッドの中の
this
は、常に Vue インスタンスを指す(アロー関数は使えないので注意する)
![lifecycle](https://vuejs.org/images/lifecycle.png =500x)
Template Syntax
- テンプレートは Valid な HTML である。
- テンプレートを使わずに、JSX と
render
ファンクションを使うこともできる。
Interpolation(Vue のデータをテンプレートに展開する)
Text
- Mustache 記法を使う
<span>Message: {{ msg }}</span>
<span v-once>This will never change: {{ msg }}</span> // 最初の1回のみ更新
<!-- 下記は機能しない。代わりにv-modelを使うこと。 -->
<textarea>{{text}}</textarea>
Raw HTML
- v-html ディレクティブを使う
<span v-html="rawHtml" />
Attributes
- 属性の中では Mustache 記法は使えない。代わりに v-bind を使う。
- null, undefined, false の場合、属性はレンダリングされない
<div v-bind:id="dynamicId"></div>
<div v-bind:active="isActive"></div>
// falsyならactiveはレンダリングされない
Javascript
テンプレートには 1 文までの Javascript を記載できる。
{{ number + 1 }} {{ ok ? 'YES' : 'NO' }} {{ message.split('').reverse().join('')
}}
<div v-bind:id="'list-' + id"></div>
Directives
v-**
がディレクティブである- ディレクティブには 1 文までの Javascript を記載できる
modifier
v-on
とv-model
には Modifier という便利なものが用意されている(後述)
Computed Properties and Watchers
computed
- 複雑な計算には
computed
プロパティを使う。 comupted
は Getter として機能する。computed
が依存するdata
がアップデートされたときは自動で再計算され、View に反映される
<p>{{ reversedMessage }}</p>
var vm = new Vue({
data: {
message: 'Hello',
},
computed: {
reversedMessage: function () {
return this.message.split('');
},
},
});
computed と method の違い
computed
と同じことはmethods
でもできる。違いは下記の通り。
computed
は、依存するdata
が変更されない限り再計算をしない(キャッシュが使われる)methods
は、常に再計算をする
computed と watch の違い
殆どの場合watch
でデータを変更するのは効率が悪い。
computed
を使え。
watch
が最適となるのは、データの変更に応じて、非同期 or 高価な処理を行う場合に限る(参考)
setter
computed
は、標準では getter としてのみ機能する。
setter を使いたいときは下記のようにする。
computed: {
fullName: {
get: function () {},
set: function (newValue) {}
}
}
Class and Style Bindings
Classes
v-bind:class
を使うことで、クラスを動的に設定できる- オブジェクトはインラインでなくても OK(外出ししてもよい)
computed
で計算したオブジェクトを使うと、便利で強力である- Array Syntax で複数の要素を指定することもできる
<div
class="some-default-class"
v-bind:class="{ active: isActive, 'text-danger': hasError }"
></div>
<!-- errorClass='some-string' -->
<div v-bind:class="[{ active: isActive }, errorClass]"></div>
Component に Class を指定したとき
Component に Class を指定したときは、そのコンポーネントのルート要素にそのクラスが設定される。
<my-component class="baz boo"></my-component>
Styles
- Class の場合とほぼ同じ
- Auto Prefix される
<div v-bind:style="styleObject"></div>
<div v-bind:style="[baseStyles, overridingStyles]"></div>
Conditional Rendering
v-if
<div v-if="type === 'A'">A</div>
<div v-else-if="type === 'B'">B</div>
<div v-else-if="type === 'C'">C</div>
<div v-else>Not A/B/C</div>
template
2 つ以上の要素にまとめて v-if を設定したいときは template を使う。
<template v-if="ok">
<h1>Title</h1>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</template>
DOM の再利用
- v-if は、DOM を再利用する。再利用させたくない場合は
key
属性を指定する。 - 下記の場合、label は再利用されるが、input は再利用されない。
<template v-if="loginType === 'username'">
<label>Username</label>
<input key="username-input" />
</template>
<template v-else>
<label>Email</label>
<input key="email-input" />
</template>
v-show
v-if との違いは下記の通り
v-if
- 条件が True になったとき、初めて内包する要素が生成される。
- 条件が False になったときは要素が削除される。
- トグルのコストが高い
- あまりトグルしないものに向いている
v-show
- template, v-else は使えない
- 条件に関係なく常に生成される。css の display を変更しているだけ。
- 初期表示のコストが高い
- 頻繁にトグルするものに向いている
v-if と v-for
v-if
とv-for
を同時に使った場合、v-for
が優先される。- つまり、
v-for
の各子要素に対してv-if
がアタッチされる
List Rendering
v-for
- Array や Object にループ処理を行った上でレンダリングするためのもの。
in
はof
に置き換えてもよい。
<!-- Array -->
<li v-for="item in array"></li>
<li v-for="(item, index) in array"></li>
<!-- Object -->
<li v-for="item in object"></li>
<div v-for="(value, key) in object">
<div v-for="(value, key, index) in object"></div>
</div>
key
リスト要素には、必ず key 要素をつけること。 (デフォルトの"in-place patch"という方法を意図的に使いたい場合を除く)