Vue 入門
Node.js(npm+Browserifyなど)でパッケージ管理したり、サーバサイドで事前処理(.vue
ファイル、vue-cli)して配信ファイルを生成したりしてややこしいけれど、基本的にVue(Vue.js)はブラウザ上で動作するBootstrap++みたいなクライアントサイドフレームワークという理解。
参考
この「はじめに」をベースにサンプルを並べていく。
何もしないHTML
<!DOCTYPE html><meta charset="utf-8"><script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script><!-- <script src="https://cdn.jsdelivr.net/npm/vue"></script> --><h2>Hello Vue!</h2><p>This is not Vue!
CDNから開発用のVue.jsを持ってくるだけ。これをベースにいじっていく(SRIは略)。
テストするときはpython3 -m http.server --bind 127.0.0.1
とか、php -S 127.0.0.1:8000
とか、静的コンテンツを開ければなんでもよし。
テンプレート的用法
適当に使ってみる
<!DOCTYPE html><meta charset="utf-8"><script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script><!-- <script src="https://cdn.jsdelivr.net/npm/vue"></script> --><h2>Hello Vue!</h2><p id="body">{{ body_content }}<script>(function() {var app = new Vue({el: '#body',data: {body_content: 'This is BODY!',},});})();</script>
Django/Jinjaのように{{ variable }}
の形式で埋め込み位置を指定。Vueオブジェクトを作って初期値を与える。
コンテナ要素で使ってみる
<!DOCTYPE html><meta charset="utf-8"><script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script><!-- <script src="https://cdn.jsdelivr.net/npm/vue"></script> --><div id="app"><h2>{{ title }}</h2><p>{{ body }}</div><script>(function() {var app = new Vue({el: '#app',data: {title: 'Hello Vue!',body: 'This is BODY!',},});})();</script>
要素の内部に複数の埋め込みを行う。
属性をテンプレート化
<!DOCTYPE html><meta charset="utf-8"><script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script><!-- <script src="https://cdn.jsdelivr.net/npm/vue"></script> --><div id="app"><h2 v-bind:title="tooltip">{{ title }}</h2><p>{{ body }}</div><script>(function() {var app = new Vue({el: '#app',data: {tooltip: 'Hover text',title: 'Hello Vue!',body: 'This is BODY!',},});})();</script>
属性(この場合、ホバーテキスト/ツールチップを表すtitle
属性)に埋め込みを行う(title
という名前が2つ出てきてややこしくなってしまった)。
スクリプトからの書き換え
<!DOCTYPE html><meta charset="utf-8"><script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script><!-- <script src="https://cdn.jsdelivr.net/npm/vue"></script> --><div id="app"><h2 v-bind:title="tooltip">{{ title }}</h2><p>{{ body }}</div><script>(function() {var app = new Vue({el: '#app',data: {tooltip: 'Hover text',title: 'Hello Vue!',body: 'This is BODY!',},});app.title = 'This is TITLE!';app.tooltip = 'This is TOOLTIP!';})();</script>
埋め込みテキストはスクリプトから変更可能(すぐに反映される)。
イベントハンドリング
クリックイベント
<!DOCTYPE html><meta charset="utf-8"><script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script><!-- <script src="https://cdn.jsdelivr.net/npm/vue"></script> --><div id="app"><h2 v-bind:title="tooltip">{{ title }}</h2><p>{{ body }}<p><button v-on:click="onButtonClicked">Switch</button></div><script>(function() {var app = new Vue({el: '#app',data: {tooltip: 'Hover text',title: 'Hello Vue!',body: 'This is BODY!',},methods: {onButtonClicked: function() {this.title = 'This is TITLE!'; // this == appthis.tooltip = 'This is TOOLTIP!';},},});})();</script>
クリックイベントが起きたとき埋め込みテキストを書き換える。
Vueの内部状態とinputタグ
<!DOCTYPE html><meta charset="utf-8"><script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script><!-- <script src="https://cdn.jsdelivr.net/npm/vue"></script> --><div id="app"><p><input v-bind:value="field1"><p><input v-model="field2"><p><button v-on:click="check">Check</button></div><script>(function() {var app = new Vue({el: '#app',data: {field1: 'Field 1',field2: 'Field 2',},methods: {check: function() {console.log(app.field1);console.log(app.field2);},}});app.check();})();</script>
Vueの内部状態と画面上の状態がずれたときの挙動を試す。v-bind:value
では再描画が走ったときに値がVueの内部状態にリセットされる。これを防ぐ(Vueの内部状態と表示状態を同期する)にはv-model
を使う(双方向バインディング)。
スタイル操作
Visibility
<!DOCTYPE html><meta charset="utf-8"><script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script><!-- <script src="https://cdn.jsdelivr.net/npm/vue"></script> --><div id="app"><p><button v-on:click="onButtonClicked">Switch</button><p v-if="message_visible">Hello Vue!</div><script>(function() {var app = new Vue({el: '#app',data: {message_visible: true,},methods: {onButtonClicked: function() {app.message_visible = !app.message_visible;},}});})();</script>
display: none
の切り替え。条件分岐という扱いらしい。
<!-- Django / Jinja -->{% if message_visible %}<p>Hello Vue!{% endif %}
これの代わりなのはわかるが、タグ名が先に来ているのが読みにくい..(Rubyか?)。
再利用
配列のマッピング
<!DOCTYPE html><meta charset="utf-8"><script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script><!-- <script src="https://cdn.jsdelivr.net/npm/vue"></script> --><div id="app"><ol><li v-for="item in items">{{ item.text }}</ol></div><script>(function() {var app = new Vue({el: '#app',data: {items: [{ text: 'Item 1' },{ text: 'Item 2' },{ text: 'Item 3' },],},});})();</script>
v-for
を付けた要素をリストに基づいて複製して個数分表示する。これもタグ名が先に来ているのが読みにくい..。
<!-- Django / Jinja --><ol>{% for item in items %}<li>{{ item.text }}{% endfor %}</ol>
これの代わりなのはわかる。
コンポーネント
新しいタグ名を定義する感覚で要素の再利用(コード上での定義)ができる。
<!DOCTYPE html><meta charset="utf-8"><script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script><!-- <script src="https://cdn.jsdelivr.net/npm/vue"></script> --><script>Vue.component('my-item', {template: '<li>Item</li>',});</script><div id="app"><ol><my-item v-for="item in items"></my-item></ol></div><script>(function() {var app = new Vue({el: '#app',data: {items: [{ text: 'Item 1' },{ text: 'Item 2' },{ text: 'Item 3' },],},});})();</script>
閉じタグ省略したら警告出た。text
をちゃんと使うには、以下のようにする。
<!DOCTYPE html><meta charset="utf-8"><script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script><!-- <script src="https://cdn.jsdelivr.net/npm/vue"></script> --><script>Vue.component('my-item', {props: [ 'my_item', ],template: '<li>{{ my_item.text }}</li>',});</script><div id="app"><ol><my-itemv-for="item in items"v-bind:my_item="item"></my-item></ol></div><script>(function() {var app = new Vue({el: '#app',data: {items: [{ text: 'Item 1' },{ text: 'Item 2' },{ text: 'Item 3' },],},});})();</script>
v-bind:text="item.text"
みたいなこともできるらしい。
Vue CLIって何
今回は単一のHTMLファイルに全部書いてるが、巨大なプロジェクトではそうもいかない。 コンポーネントの定義なんかは外部のJSを持ってくればよさそうだけれど、これも数が多くなると管理がつらくなってくる。 このへんをなんかいい感じ(コンポーネントごとにファイル分けたり)にして、ついでにURL(パス、ルーティング)もいい感じにできる(JSでルーティング設定)ようにして、最終的にブラウザ側でVueの処理をいい感じにできるように整えた静的サーバコンテンツ(GitHub Pagesとかで動くやつ)を生成するツールを作ってみた、というのがVue CLIっぽい。