【超Vue.js】Vueインスタンスとその内部構造はこうなっている【セクション4 】
50. イントロダクション
Vueインスタンス
Vueインスタンスって複数作れるの?他のjsからアクセスできるの?とかの内容
51. Vue インスタンスは複数作ることができる
Vueインスタンスはなるべく複数使用しない方がいい
完全に独立してるなら使ってもおk。
#app2
押すと、#app1
に何らかの処理が起きるとかはやめよう。そのような処理は一つのインスタンスの中(#app1の中)にまとめる。
52. 外側からVue インスタンスにアクセスする方法
<div id="app1"> <p>{<200c>{ message }}</p> </div> <div id="app2"> <p>{<200c>{ message }}</p> <button @click="changeMessage1">変更</button> </div> // 変数を設定 var vm1 = new Vue({ el: '#app1', data: { message: 'インスタンス1' } }) // 変数を設定 var vm2 = new Vue({ el: '#app2', data: { message: 'インスタンス2' }, methods: { changeMessage1: function() { // #app2から#app1のインスタンスにアクセス vm1.message = 'インスタンス2からアクセスして変更しました' } } })
53. リアクティブシステム(getter、setter、Watcher)がどのように動いているかを確認し、プロパティを後から追加できないことを理解する
外部から新しいプロパティの追加はできない
厳密に言うとリアクティブにならない
リアクティブ=Vue側のデータが変わると、HTMLのデータも変わる(ブラウザの表示が変わる)。これはvueがやってくれている。
リアクティブになる理由
まずインスタンス内のdataに、リアクティブにしたいプロパティを最初に置いておく。以下ではmessage
。
Vue.jsがやってくれることは、インスタンスのプロパティウォッチャを作ってくれる(=getterとsetterを用意してくれる)
getter...その変数(プロパティ)が参照された時に、関数を実行する
setter...その変数(プロパティ)が変更された(書き換わった)時に、関数を実行する。
ウォッチャとは...getter,setterをトリガーに関数を実行してくれる。
var vm = new Vue({ el: '#app', data: { message: 'こんにちは' } }) // インスタンス生成後に、インスタンスの外部から後付けで作ったプロパティ vm.name = 'よしぴー' console.log(vm);
上記を書いてconsoleをみてみると、以下がある。
get message: ƒ proxyGetter() set message: ƒ proxySetter(val)
→これがあるから、リアクティブになる!!
一方で、外部から作ったプロパティvm.name
にはgetterとsetterがない、つまり、clickイベントで値を変えようとしても変わらないのです。
54. Vueインスタンスプロパティの$dataの紹介
Vueインスタンスが使えるようなメソッドは$メソッド
という形になっている。
外部のデータを、インスタンス内にセットすることはできる。
// 外部のデータ var data = { message: 'こんにちは' } var vm = new Vue({ el: '#app', // valueに上記の変数dataを入れている data: data }) console.log(data === vm.$data); console.log(vm);
55. インスタンスの内側から、Vueインスタンスのプロパティやメソッドにアクセスする
内部からはthis
var data = { message: 'こんにちは' } var vm = new Vue({ el: '#app', data: data, computed: { myData: function() { return this.$data; } } })
56. VueのAPI一覧はここに載っています。
Vueインスタンスのプロパティやメソッドはどう使うのかなあ
→公式のAPI一覧を見よう!!
57. $mountメソッドを使用して、elプロパティの代わりにする
$mount
たまに使う。el
プロパティの代わりになる
// まだインスタンス内で、elで指定していない var vm = new Vue({ data: data, computed: { myData: function() { return this.$data; } } }) // ビューテンプレートを指定している(マウントしている) vm.$mount('#app')
58. templateプロパティを使って、文字列のみでテンプレートを書く
テンプレートの書き方は3種類ある
1. 普通の書き方
<p>{<200c>{ message }}</p> <button @click="message = 'ボタンから変更'">変更</button>
2. templateプロパティ(この書き方は複数行あると大変)
<div id="app2"></div> new Vue({ el: '#app2', data: { name: 'りょうた' }, // teplateプロパティの値に、そのまま全部文字列として入れる template: '<p>こんにちは、{<200c>{ name }}</p>' })
$mount
を末尾に付けても同じように書ける
new Vue({ data: { name: 'りょうた' }, template: '<p>こんにちは、{<200c>{ name }}</p>' }).$mount('#app2')
3. render関数(次回)
59. render(描画)関数を使用して、仮想ノードを作ってDOMの描画を行う
render関数
createElementはデフォルトで使える
<div id="app3"></div> new Vue({ data: { name: 'りょうた' }, render: function(createElement) { // createElementはメソッドになっている return createElement('h1', 'こんにちは' + this.name); }, }).$mount('#app3')
以下のようにh
で書くことも多い
render: function(h) { return h('h1', 'こんにちは' + this.name);
上記はdocument.createElementのcreateElementとは全くの別物
DOM
var dir = document.createElement('div'); console.log(dir); console.log(document); console.dir(document);
documentはdocument(=ブラウザ)がHTMLを受け取ってDOMに変換してオブジェクトにしてくれる。
objectはキーと値
modelは形
DOMを読み取ってHTMLぽく表示してくれる
return createElement('h1', 'こんにちは' + this.name)
は仮想Nodeを作っている。
→VNodeは仮想Node→オブジェクト(ただの情報=文字列)を返している
→DOMを触っていない
→仮想DOMを作る
document.createElement('div');は直接DOMにアクセスしている
仮想DOMと、その必要性を理解する
仮想DOMを作るために仮想Nodeを返す
仮想DOM...DOM要素を模したJS用のオブジェクト
何故使う?
ボタンを推した時に表示が変わるようにする
→変更する時に、部分的にDOMを使うのが効率良い
→DOMを一回作って、新しく作ったDOMと見比べて、変更がある箇所(差分)だけ変える、この新しいDOMを作るのがめっちゃ効率悪い。
→仮想的なDOM(自分のjsで仮想的なDOMオブジェクト)を作って、前の仮想DOMと見比べて変更する。効率が良い。
普通のDOM
DOMにアクセスして、追加、削除、変更とかするからめっちゃ遅い。パフォーマンス悪い。
→普通のDOMはブラウザにあるから(documentとか)、DOMにアクセスする=ブラウザにアクセスするから遅い
62. Vue インスタンスライフサイクルの全体像を見て、Vueがどのように動いているかを理解する
ライフサイクル
Vuejsが作られてから、どのような動きをして〜までの流れ。
- new Vue()...beforeCreate()
- インスタンスが作られる(データがリアクティブになる)...created() (elがあるかどうか)
- ある場合、templateをrender関数にコンパイル(ない場合、vm.$mountが呼ばれた時に、templateをrender関数にコンパイル)
- $elを作って実際のDOMに追加
- mounted(⇄データが変わるとDOMを再描画)
- Destroyed(手動でやることは基本ない)
63. ライフサイクルフックのタイミングを実際にコードで確かめる
<div id="app4"> <p>こんにちは、{<200c>{name}}</p> <button @click="name = '太郎'">名前変更</button> <button @click="destroy">インスタンスを破壊</button> </div> new Vue({ el: '#app4', data: { name: 'りょうた' }, beforeCreate: function() { console.log('beforeCreate'); }, created: function() { console.log('Created'); }, beforeMount: function() { console.log('beforeMount'); }, mounted: function() { console.log('mounted'); }, beforeUpdate: function() { console.log('beforeUpdate'); }, updated: function() { console.log('updated'); }, beforeDestroy: function() { console.log('beforeDestroy'); }, destroyed: function() { console.log('destroyed'); }, methods: { destroy: function() { this.$destroy() } } })
64. コンポーネントを使用して、同じようなインスタンスを使い回す
コンポーネントを登録した後に、インスタンスで使う
Vue.component('hello', { template: '<h1>こんにちは</h1>' });
<div id="app"> <hello></hello> <hello></hello> </div> var data = { message: 'こんにちは' } Vue.component('hello', { template: '<h1>こんにちは</h1>' }); var vm = new Vue({ data: data, computed: { myData: function() { return this.$data; } } }) vm.$mount('#app')