こんにちは、ほそ道です。
今回はMV**なフレームワークのひとつであるVue.jsを取り上げてみます。
さて、どこから手をつけたら良いものかと思案にくれた結果、序論や諸注意点をアレコレ展開する前にまずはビシバシと弄って、ヒジョーにシンプルなサンプルをいっぱい作って体にしみ込ませてみるのがイイんじゃないかと思いました。
ボリュームがあるので何回かに分け、今回はビューモデルを生成するパターンをまとめます。
「考えるな、感じろ」の精神でやった後にどう考え学習すべきかや、どう設計すべきかなどの私見は述べられたら良いなと思っております。
ViewModel生成編
ディレクティブ編
[インスタンスメンバ編]
(http://qiita.com/setzz/items/ebbfcc3565bcd27f344c)
[グローバルメソッド編]
(http://qiita.com/setzz/items/8f06f2fe6049173b17f9)
[フィルター編]
(http://qiita.com/setzz/items/e37c47d3f22e5738eb84)
[v-repeatネスト編]
(http://qiita.com/setzz/items/6f22ebd15bcc0afe1ab0)
全体の目次はこちら
ザックリとしたVue.js概念
- IE8以下には非対応
- MVVMアーキテクチャにフォーカスしている
- MVVMとはモデル(M)とビュー(V)間のやり取りをビューモデル(VM)によって行うアーキテクチャらしい
Vueインスタンスの生成
Vueインスタンス
ビューモデルというのを作ってDOM要素にバインドするのが基本的な流れのようです。
サンプルコードはHTMLのbody要素におブチ込み頂けると動くかと思います。
ちょいちょいv-というディレクティブが入ってきますが次回やるので今回はさらっと流します。
el,dataオプション
まずは基本のサンプルとしてel,dataオプションを使ってみます。
データバインディングを体で感じでみます。
オプション | 説明 |
---|---|
el | セレクタを使ってバインド先のDOM要素を指定する |
data | ビューモデルが保持するデータ群。 |
<div id="sample">
<div v-text="bind1"></div>
<div v-model="bind2"></div>
<div>{{bind3}}</div>
</div>
<script src="js/vue.js"></script>
<script>
var vm = new Vue({
el: '#sample',
data: {
bind1: '111',
bind2: '222',
bind3: '333'
}
});
</script>
- new Vue()でビューモデルを作成する
- elでDOM要素を指定し、ビューモデルの適用範囲を指定する
- ビューモデルのdataオブジェクトの属性はv-textやv-modelディレクティブによってバインドされる
-
vm.$el
やvm.$data
でビューモデルの属性にアクセス出来る -
vm.$data
やvm.$methods
はvm
でアクセスも可能 - ブラウザコンソールから
vm.bind1 = 100;
と叩けば画面の表示も遷移無しに変更される
今回、dataの中にはただのデータを突っ込んでいますが、モデルはこの中に定義するのもやり方としてあるようです。
また、疑問に思ったのでやってみたのですが1つのDOM要素に複数のビューモデルがバインドされた際には先にバインドしたビューモデルが勝つようです。
とりあえずビュー側(div要素)にv-textやv-modelディレクティブというのが出てきますが今回の対象外なので、あーなんかうまい事データバインドするのね、くらいの理解にとどめます。
methods,computedオプション
固定の値だけではなく、動的な値をデータバインドするときにはこんなオプションが使えるようです。
オプション | 説明 |
---|---|
methods | ビューモデルのメソッドを保持するオブジェクト。methodsに限らないがビューモデル内で定義されたメソッド内でのthisはビューモデル自身を指す |
computed | 動的なプロパティを生成するメソッドを持つオブジェクト。methodsとの違いとして呼び出しに括弧を用いずプロパティであるかのようにアクセス出来る。またgetやsetの定義が出来る |
- methodsはビューからは括弧付きで呼び出される
<div id="sample">
<div v-text="fullName()"></div>
</div>
<script src="js/vue.js"></script>
<script>
var user = new Vue({
el: '#sample',
data: {
firstName: 'Taro',
lastName: 'Yamada'
},
methods: {
fullName: function() {
return this.firstName + ' ' + this.lastName;
}
}
});
</script>
- computedは括弧無しであたかもプロパティであるかのようにアクセス出来る
<div id="sample">
<div v-text="fullName"></div>
</div>
<script src="js/vue.js"></script>
<script>
var user = new Vue({
el: '#sample',
data: {
firstName: 'Taro',
lastName: 'Yamada'
},
computed: {
fullName: {
get: function() {
return this.firstName + ' ' + this.lastName;
}
}
}
});
</script>
methodsとcomputedの使い分け
最終的には、2つのアプローチは完全に同じ結果になります。
しかし、computedプロパティは依存関係にもとづきキャッシュされるという違いがあります。computedプロパティは、依存するものが更新されたときにだけ再評価されます。つまり、dataで定義された中身が変わらない限り、computedプロパティで定義された関数に何度アクセスしても、再び実行することなく以前計算された結果を即時に返します。
Date.now() はリアクティブな依存ではないため、次の算出プロパティは二度と更新されません:
computed: {
now: function () {
return Date.now()
}
}
対称的に、メソッド呼び出しは、再描画が起きると常に関数を実行します。
paramAttributesオプション
el要素の属性を取得できます。
オプション | 説明 |
---|---|
paramAttributes | 配列形式でHTML要素の属性名を列挙するとビューモデルのプロパティとして格納される |
- 属性の取得
<div id="sample" style="font-size:30px">foo</div>
<script src="js/vue.js"></script>
<script>
var vm = new Vue({
el: '#sample',
paramAttributes: ['style']
});
console.log(vm.style); // font-size:30px
</script>
template, replaceオプション
テンプレートを使う事でHTMLの内容を書き換えます
オプション | 説明 |
---|---|
template | $elで指定した要素に挿入されるHTML文字列 |
replace | templateとセットで使う事で$el要素自体を置換するかをbool値で指定する |
- el要素の内側をテンプレートで置換(上記のサンプルでは元々のdiv要素は存在し続け、内側のfooが置換されます。)
<div id="sample">foo</div>
<script src="js/vue.js"></script>
<script>
var vm = new Vue({
el: '#sample',
template: '<div>bar</div>'
});
console.log(vm.style); // font-size:30px
</script>
- replaceを使うと置換される事でel要素が破棄される
<div id="sample">foo</div>
<script src="js/vue.js"></script>
<script>
var vm = new Vue({
el: '#sample',
template: '<div>bar</div>',
replace: true
});
</script>
tagName, id, className, attributesオプション
ここまではel要素はあらかじめ存在するものとして扱ってきましたが、生成し挿入する事も出来ます。
インスタンス生成時のelオプションを省略するとデフォルトでは空のdiv要素がel要素として生成されます。下記はそのカスタマイズオプションです。
オプション | 説明 |
---|---|
tagName | elを省略したときに自動生成される要素をdiv以外で指定出来る |
id | $el要素のid属性で文字列で指定する |
className | $el要素のclass属性で文字列で指定する |
attributes | $el要素の属性でオブジェクトリテラルで指定する |
- elの指定を省略すると自動でdivタグが生成され、これはDOM要素としてJSで扱う事が出来る。この時にid,className,attributesで属性の指定が出来る。
<script src="js/vue.js"></script>
<script>
var vm = new Vue({
tagName: 'p',
id: 'foo',
className: 'bar',
attributes: {
style: 'font-size:30px'
},
template: 'display text'
});
document.body.appendChild(vm.$el);
</script>
<p id="foo" class="bar" style="font-size:30px">display text</p>
今回、あえてDOMメソッドのAppendChildを使ってますが、DOM要素の追加はvm$.appendTo(追加先DOM要素);
などでやるのがVue.jsのお作法なようです。
イベントフックな関数定義オプション
ビューモデルに特定の状態が発生したときに実行されるコールバック関数の定義オプションです。
今回はcreatedとattachedを取り上げてみます。
オプション | 説明 |
---|---|
created | ビューモデルの初期化時、データバインド前に実行される関数。$dataに動的なプロパティを追加出来る。関数内でthis.$watch メソッドを呼び出すとメソッド引数として渡したコールバック関数がデータバインド時に実行される |
ready | データバインドが完了した状態で実行される関数。$dataへのプロパティ追加は無視される |
attached | $el要素がDOMツリーに追加されたときに呼ばれる関数 |
detatched | $el要素がDOMツリーから削除されたときに呼ばれる関数 |
beforeDestroy |
vm.$destroy() 関数が呼ばれビューモデルが破棄される前に呼ばれる関数 |
afterDestroy |
vm.$destroy() 関数が呼ばれビューモデルが破棄された後に呼ばれる関数 |
createdオプション
- オブジェクト定義時に$dataにデータを定義。
<div id="sample" v-text="value"></div>
<script src="js/vue.js"></script>
<script>
var vm = new Vue({
el: '#sample',
created: function() {
this.$data.value = 'Hello!';
}
});
</script>
- $watchを使ってデータバインド時のコールバックを行う
- ページ表示後にブラウザコンソールで
vm.value = 'Bye!';
などと叩けば再度コールバックは実行される
<div id="sample" v-text="value"></div>
<script src="js/vue.js"></script>
<script>
var vm = new Vue({
el: '#sample',
data: {
value: 'Hello!'
},
created: function() {
this.$watch('value', function(newValue) {
console.log('reset data: ' + newValue);
});
}
});
</script>
attachedオプション
- ページ表示後にブラウザコンソールで
vm.$appendTo(document.body);
を叩くとアラートが表示される。DOMメソッドのappendChildや$el要素のアクセスでは関数は実行されない。
<script src="js/vue.js"></script>
<script>
var vm = new Vue({
attached: function() {
alert('ViewModel is attached!');
}
});
</script>
カスタムパーツ
オプション | 説明 |
---|---|
directives | カスタムディレクティブを提供する |
filters | カスタムフィルタを提供する |
components | 部品化したDOM要素を提供する |
partials | 既存のDOM要素を部品化して再利用出来る |
transitions | CSSトランジション(使い方がわからなかった。。) |
directiveオプション
<div id="sample" v-consolelog="foo">Hello!</div>
<script src="js/vue.js"></script>
<script>
var vm = new Vue({
el: '#sample',
data: {
foo: 'CustomDirective',
},
directives: {
consolelog: function(value) {
console.log(value);
}
}
});
</script>
filtersオプション
<div id="sample">
<span v-text="foo | mysort"></span>
</div>
<script src="js/vue.js"></script>
<script>
var vm = new Vue({
el: '#sample',
data: {
foo: [4, 2, 3, 1, 5]
},
filters: {
mysort: function(value) {
return value.sort()
}
}
});
</script>
componentsオプション
componentはelで指定した要素の内側には使用できるがel要素自体に使おうとすると警告が発生する
<div id="sample">
<span v-component="foo"></span>
</div>
<script src="js/vue.js"></script>
<script>
var vm = new Vue({
el: '#sample',
components: {
foo: {
template: '<p>Component</p>'
}
}
});
</script>
partialsオプション
- partialsにアクセスするにはv-partial以外にも{{> property}}という記述も可能
<div id="sample">
<span v-partial="foo"></span>
<span>{{> foo}}</span>
</div>
<div id="other">OTHER</div>
<script src="js/vue.js"></script>
<script>
var vm = new Vue({
el: '#sample',
partials: {
foo: '#other'
}
});
</script>
parentオプション
オプション | 説明 |
---|---|
parent | ビューモデルに親子関係を持たせる。子は親のデータにアクセス可能 |
<div id="sample">
<span v-text="foo"></span>
<span v-text="bar"></span>
</div>
<script src="js/vue.js"></script>
<script>
var parent= new Vue({
data: {
bar: 'BAR'
}
});
var child = new Vue({
el: '#sample',
parent: parent,
data: {
foo: 'FOO'
}
});
</script>
lazyオプション
オプション | 説明 |
---|---|
lazy | INPUT編集時などに、同期的に値が書き換えられず、フォーカスを外れてからデータが更新される |
<form id="sample" action="">
<div v-text="foo"></div>
<input type="text" v-model="foo">
</form>
<script src="js/vue.js"></script>
<script>
var vm = new Vue({
el: '#sample',
data: {
foo: 'defaultValue',
},
lazy: true
});
</script>
===
今回は以上です。
結構手探り間がありますが、体で覚え中なので致し方ないかなと、とにかく前に進むのみ!
次回はディレクティブを体で覚えていきたいと思います。