イベント
イベントハンドラ
メソッド名、または式を記述する。
<button v-on:click="handleClick">メソッド名を指定</button>
<button v-on:click="handleClick()">メソッドコールを記述</button>
メソッド名を指定した場合、引数でイベントオブジェクトを受け取ることができる。(JavaScriptの通常の動き)
handleInput(e) {console.log(e);}
メソッドコールを記述した場合、$eventという変数名でイベントオブジェクトにアクセスすることができる。
<button v-on:click="eventTest($event, 100)">$eventテスト</button>
eventTest(e,num) {
console.log(e); console.log(num);
}
イベント修飾子
- .prevent
event.preventDefault() - .stop
event.stopPropagation() - .self
自分自身のときだけハンドラ実行
モーダルの背景をクリックして閉じる場合に便利 - .right
クリックイベントで右ボタンのときだけハンドラ実行
キー修飾子
キーコードまたはエイリアスで指定可能。v-on:keydown.13
v-on:keydown.enter
複数指定するとORになる。v-on:keydown.up.down
システム修飾子
対応するキーが押されている場合のみイベントハンドラが呼び出される。
- .ctrl
- .alt
- .shift
<button v-on:click.shift="doDelete">削除</button>
inputイベント
v-modelディレクティブは、日本語入力の場合は変換確定するまでデータを更新しない。確定前に更新したい場合はinputイベントを使うとよい。
<input v-on:input="handleInput">
methods: {
handleInput: function (event) {
console.log(event.target.value);
}
}
テキストエリア
テキストエリアはMustacheを使ったバインディングはできない。v-modelを使用する。
<textarea>{{ msg }}</textarea><!--とはできない。-->
<textarea v-model="msg"></textarea><!--とする。-->
単一チェックボックス
デフォルトでは値はBoolean型となる。
<input type="checkbox" v-model="val">{{ val }}
値を自分で設定したい場合は、true-value, false-value属性を使う。
<input type="checkbox" v-model="val" true-value="OK" false-value="NG">{{ val }}
複数チェックボックス
配列型となる。v-modelディレクティブに同じ配列変数を指定し、value属性に値を設定する。
data: {
val: []
}
<input type="checkbox" v-model="val" value="A">A
<input type="checkbox" v-model="val" value="B">B
<input type="checkbox" v-model="val" value="C">C
<p>{{ val }}</p>
ファイルアップローダ
ファイルアップローダ(type=”file)はv-modelディレクティブを使用できない。
リアクティブにするにはv-on:change=”xxx”としてchangeイベントをハンドルする必要がある。
<input type="file" name="file" v-on:change="uploadFile">
<img v-bind:src="imgBinary">
uploadFile(e) {
this.imgBinary = window.URL.createObjectURL(e.target.files[0]);
},
v-modelの修飾子
- .number
数値に変換 - .trim
前後の改行・スペースを削除(全角スペースも) - .lazy
- inputイベントではなくchangeイベントをハンドルする
マウント要素外のイベントハンドリング
windowやbodyではv-onを使用できないので、普通にaddEventListener(またはjQueryなど)を使う。v-onのように自動で解除されないため、フックを使って解除する必要がある。 例えば、createdでwindow.addEventListener()
とし、beforeDestroyでwindow.removeEventListener()
とする。
応用
算出プロパティ
Mustacheやディレクティブの式を算出プロパティにすると可読性が上がる。 computedオプションに関数として定義するが、プロパティとして使用できる(内部でdefinePropertyが呼ばれているため)
computed: {
halfWidth: function() {
return this.width / 2;
}
}
算出プロパティのキャッシュ機能
算出プロパティは、参照しているリアクティブデータが更新されたときだけ再評価される。
methods: {
methodsRandom: function () {
return Math.random();
},
},
computed: {
computedRandom: function () {
return Math.random();
},
}
// computedRandomは毎回同じ値を返却する。
ウォッチャ
変数を監視して変化があったときに処理を実行することができる。ただし、多くの場合は算出プロパティを使った方がよい(https://jp.vuejs.org/v2/guide/computed.html)
データが変わるのに応じて、非同期やコストの高い処理を実行したいときに最も便利。
watch: {
question: function (newQuestion, oldQuestion) {
this.doSomthing();
}
},
フィルタ
文字数を丸めたり、数字にカンマを入れたりできる。コンポーネントのfilterオプションに算出プロパティのように定義し、Mustacheまたはv-bindディレクティブの値にパイプでフィルタ名をつなぐ。
※thisへのアクセスはできない
thisへのアクセス可否以外はcomputedと同じだが、テキストの変換はfiltersに定義した方が管理しやすくなる。
filters: {
localNum: function(val) {
return val.toLocaleString();
}
}
// として
// {{ price | localNum }} 円
// で表示。
localNum: function(val、name, num) {
return `${val}:${name}:${num}`;
}
// のように第2引数以降に引数を持たせることもできる。
// {{ price | localNum('Taro', 100) }}
グローバルフィルタ
Vue.filterメソッドを使って登録すると、すべてのコンポーネントから利用できる。
Vue.filter('localNum', function(val) {
return val.toLocaleString();
});
コンポーネント
コンポーネントのグローバル登録
Vue.componentメソッドを使う。
※templateのルート要素は1つでなければならない
Vue.component('my-component', {
template: '<p>MyComponent</p>'
});
<!--使用する際はタグとして記述する。-->
<my-component></my-component>
コンポーネントのローカル登録
new Vue()する際のcomponentsオプションに登録することで、スコープを制限できる。通常はローカル登録を使うべき。
new Vue({
el: '#app',
components: {
'my-component': {template: '<p>My Component</p>'}
}
});
コンポーネントのオプション
new Vue()と同じように、data, methods, computed, watchなどを定義できる。ただし、dataはオブジェクトではなくオブジェクトを返す関数にする必要がある。
components: {
'my-component': {
template: '<div><p>Option test</p><button v-on:click="doComponentMethod"></button>{{ msg }}</div>',
data: function() {
return {
msg: 'hoge'
}
},
methods: {
doComponentMethod: function() {
this.msg = 'doComponentMethod called';
}
},
},
}
コンポーネント間の通信
方法は3つ。
- popsとカスタムイベントを使った親子間通信
- イベントバスを使った非親子間通信
- Vuexを使った状態管理
親子コンポーネント
テンプレートで他のコンポーネントを使用すると親子関係になる。
Vue.component('parent-child', {
template: '<div><global-component></global-component></div>'
}
);
グローバル登録だと読み込むコンポーネントが多くなってしまうため、ローカル登録するべき。ただし、ローカル登録されたコンポーネントは、他のコンポーネント内では使用できない。 以下のように、componentsに子テンプレートをセットする必要がある。
let childComponent = {template: '<p>childComponent</p>'};
let parentComponent = {
template: '<p><child-component></child-component></p>',
components: {
'child-component': childComponent
},
};
として、new Vueの中で以下のようにする。
components: {
'parent-component': parentComponent
},
※コンポーネントをJavaScriptオブジェクトとして定義し、componentsに使うものをセットしてあげる
propsオプション(親から子へ)
propsオプションにより、属性としてコンポーネントに値を渡すことができる。
let parentComponent = {
template: '<div><child-component v-bind:val="val"></div>',
components: {
'child-component': childComponent,
},
props: ['val'],
};
<parent-component val="abc"></parent-component>
<parent-component v-bind:val="msg"></parent-component>
※propsで受け取ったデータは上書きできない。データを変更したい場合はcomputedで新しいデータを作成するか$emitで親のアクションを実行する。
コンポーネントをリストレンダリング
let listComponent = {
template: '<li>{{ name }}</li>',
props: ['name'],
};
<ul>
<list-component v-for="item in items" v-bind:name="item"></list-component>
</ul>
カスタムイベント(子から親へ)
親のテンプレートで以下のように記述する。
<comp-child v-on:childs-event="parentsMethod"></comp-child>
以下のようにイベントハンドラを定義。
methods: {
parentsMethod: function(msg) {
alert(msg);
}
}
子では下記のようにthis.$emit('childs-event')
でイベント発火できる。
※第2引数以降でデータを渡すことができる
method: {
handleClick: function() {
this.$emit('childs-event', 'hogehoge');
}
}
その他
トランジション
transitionタグで囲むと、要素の追加・削除のタイミングでクラスを動的に付けてくれる。
<transition><p v-show="show">トランシジョンテスト</p></transition>
以下のようなCSSを定義しておけばよい。
.v-enter-active, .v-leave-active {
transition: opacity 1s;
}
.v-enter, .v-leave-to {
opacity: 0;
}
※初期描画時にも付与したい場合は<transition appear>
とする
※<transition>
は単一要素の場合のみ使える。複数要素の場合は<transition-group>
アプリケーションの拡張に必要な技術
- Vuex
複数のコンポーネントを管理するためのライブラリ - Vue Router
SPA用に画面とURLを紐付けるためのライブラリ。
VuexとVue Routerは独立しているが、組み合わせることで効率的な管理ができるため同時に導入することが多い。 - Vue CLI
Vue.jsのためのコマンドラインインターフェース。
開発環境にツールやライブラリを簡単に導入できる。
雛形の作成やビルドもしてくれる。
モジュール化されたJavaScriptファイル(Vue.jsの場合は単一ファイルコンポーネント)は単純に結合するだけでは動かない。
webpackのようなバンドルツールを使って依存関係を解決しながら結合する必要がある。webpackの環境構築はとても複雑で、webpack以外のツールの知識も必要になってしまう。そこで、設定ファイルを自動作成し、環境構築してくれるのがVue CLI。 Vue CLIを使えば専門的な知識がなくても単一ファイルコンポーネントを使用するための環境を作ることができる。
単一ファイルコンポーネント
HTML, JavaScript, CSSを.vueファイルにまとめて管理することができる。中規模以上の開発では単一ファイルコンポーネントがメインになる。独自フォーマットのため、コンパイルしなければならない。templateタグはコンポーネントオプションのtemplateを抜き出したもの。scriptタグはそれ以外のオプション。
<template>
<p class="title">{{ msg }}</p>
</template>
<script>
export default {
name: 'Example',
data() {
return {
msg: 'hoge',
};
},
};
</script>
<style scoped>
.title {
color: red
}
</style>
ES2015モジュールの書き方
export default 'Yamada';
export const name1 = 'Tanaka';
のように定義し、以下のようにして使う。
import User, { name1 } from './User';
console.log(User); // Yamada
console.log(name1); // Tanaka
// <script type="module">としないと動かない
- export defaultで公開した値
中括弧なしでimportすることができる。
どんな名前でimportしてもよい。
※export defaultで公開できるのは1ファイル1つ - exportで公開した値
中括弧をつけてimportしなければならない。
export時の変数名でimportする。
※{ xxx as yyy }とすることで任意の変数名に変えることができる
Babel
ES6以降の記法を、対応ブラウザの多いES5準拠へ変換するトランスパイラ。あくまでBabel自体(babel-core)は構文変換しか行わない。Babelはcore-jsというブラウザ標準APIのPolyfillと組み合わせることでES2015(ES6)の構文への対応を行っている。つまりBabelによるトランスパイルの動作は、「構文変換+Polyfill」によって実現されている。 最新のAPIなどを使用したいというよりは、開発時に新しい記法を使って書けるようにするのが目的。Vue CLIはBabelの基本設定を自動的に行ってくれる。
Vue CLIの導入
sudo npm install -g vue-cli
でインストールvue init テンプレート名 プロジェクト名
でプロジェクト作成
テンプレート名はwebpackとwebpack-simpleがよく使われる。
例)vue init webpack sample-app
(Vue CLI3ではvue create sample-app
)
いくつか質問されるが、すべてEnterとnでOK。
ディレクトリがいくつか作成されるが、触れるのはsrcだけ。
.vueファイルはsrc/components/にまとめる。cd sample-app
で移動しnpm run dev
で開発サーバを起動
(Vue CLI3ではnpm run serve
)
http://localhost:8080/で確認可能。
※webpack-simpleの場合は起動前にnpm install
が必要だった
ホットリロード機能により、修正はリロードしなくてもブラウザを反映される。 npm run build
でdistディレクトリにWEBサーバへのアップ用のファイルが生成される。
ES2015で書いてみよう
- 変数はconst、上書きが必要なものだけlet、varは使わない
constで宣言した配列でもpushなどは使える。
初期化は.length=0
とする、空配列[]の再代入はできない。 - thisが必要な場面以外ではfunctionキーワードは使わない
hoge: function(){}
は短縮記法でhoge(){}
と書く。function name(引数) {処理}
はconst name = (引数) => {処理};
と書く。