ガイド
基本的な使い方
- インストール
- はじめに
- Vue インスタンス
- テンプレート構文
- 算出プロパティとウォッチャ
- クラスとスタイルのバインディング
- 条件付きレンダリング
- リストレンダリング
- イベントハンドリング
- フォーム入力バインディング
- コンポーネントの基本
コンポーネントの詳細
- コンポーネントの登録
- プロパティ
- カスタムイベント
- スロット
- 動的 & 非同期コンポーネント
- 特別な問題に対処する
トランジションとアニメーション
- Enter/Leave とトランジション一覧
- 状態のトランジション
再利用と構成
- ミックスイン
- カスタムディレクティブ
- 描画関数とJSX
- プラグイン
- フィルター
ツール
- 単一ファイルコンポーネント
- テスト
- TypeScript のサポート
- プロダクション環境への配信
スケールアップ
- ルーティング
- 状態管理
- サーバサイドレンダリング
- セキュリティ
内部
- リアクティブの探求
移行
- Vue 1.x からの移行
- Vue Router 0.7.x からの移行
- Vuex 0.6.x から 1.0 への移行
その他
- 他のフレームワークとの比較
- Vue.js コミュニティへ参加しましょう!
- チームに会おう
v2.x 以前のドキュメントです。 v3.x のドキュメントを見たい場合はこちら
カスタムイベント
最終更新日: 2018年10月24日
このページは コンポーネントの基本 を読まれていることが前提になっています。コンポーネントを扱った事のない場合はこちらのページを先に読んでください。
イベント名
コンポーネントやプロパティとは違い、イベント名の大文字と小文字は自動的に変換されません。その代わり発火されるイベント名とイベントリスナ名は全く同じにする必要があります。例えばキャメルケース(camelCase)のイベント名でイベントを発火した場合:
this.$emit('myEvent')
ケバブケース(kebab-case)でリスナ名を作っても何も起こりません:
<!-- 動作しません -->
<my-component v-on:my-event="doSomething"></my-component>
コンポーネントやプロパティとは違い、イベント名は JavaScript 内で変数やプロパティ名として扱われることはないので、キャメルケース(camelCase)やパスカルケース(PascalCase)を使う理由はありません。さらに DOM テンプレート内の v-on
イベントリスナは自動的に小文字に変換されます (HTML が大文字と小文字を判別しないため)。このため v-on:myEvent
は v-on:myevent
になり myEvent
にリスナが反応することができなくなります。
こういった理由から いつもケバブケース(kebab-case)を使うこと をお薦めします。
v-model
を使ったコンポーネントのカスタマイズ
2.2.0から新規追加
デフォルトではコンポーネントにある v-model
は value
をプロパティとして、input
をイベントして使いますが、チェックボックスやラジオボタンなどのインプットタイプは value
属性を別の目的で使う事があります。model
オプションを使うことでこういった衝突を回避する事ができます。
Vue.component('base-checkbox', {
model: {
prop: 'checked',
event: 'change'
},
props: {
checked: Boolean
},
template: `
<input
type="checkbox"
v-bind:checked="checked"
v-on:change="$emit('change', $event.target.checked)"
>
`
})
このコンポーネントで v-model
を使う場合:
<base-checkbox v-model="lovingVue"></base-checkbox>
lovingVue
の値が checked
プロパティに渡ります。 <base-checkbox>
が change
イベントを新しい値で発火した時に lovingVue
プロパティが更新されます。
checked
プロパティをコンポーネント内の プロパティ
オプション内でも宣言する必要がある事を注意してください。
コンポーネントにネイティブイベントをバインディング
コンポーネントのルート要素にあるネイティブイベントを購読したい場合もあるかもしれません。こういった場合は .native
修飾子を v-on
に付けてください。
<base-input v-on:focus.native="onFocus"></base-input>
このやり方が役に立つこともありますが、<input>
など特定の要素を購読したい場合はあまりいいやり方ではありません。例えば上にある <base-input>
コンポーネントがリファクタリングされた場合、ルート要素は <label>
要素になってしまうかもしれません:
<label>
{{ label }}
<input
v-bind="$attrs"
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
</label>
このような場合は親にある .native
リスナは静かに動作しなくなります。エラーは何も出力されませんが、onFocus
ハンドラが呼ばれるはずの時に呼ばれなくなります。
この問題を解決するために Vue は $listeners
というコンポーネントで使えるリスナオブジェクトの入ったプロパティを提供しています。例えば:
{
focus: function (event) { /* ... */ }
input: function (value) { /* ... */ },
}
$listeners
プロパティを使うことで、コンポーネントの全てのイベントリスナを v-on="$listeners"
を使って特定の子要素に送ることができます、<input>
の様な要素の場合は v-model
を使って動作させたいでしょう。以下の inputListeners
の様に新しい算出プロパティを作った方が便利なことも多いです。
Vue.component('base-input', {
inheritAttrs: false,
props: ['label', 'value'],
computed: {
inputListeners: function () {
var vm = this
// `Object.assign` が複数のオブジェクトを一つの新しいオブジェクトにマージします
return Object.assign({},
// 親からの全てのリスナを追加します
this.$listeners,
// そしてカスタムリスナを追加したり
// すでに存在するリスナの振る舞いを変えることができます
{
// こうすることでコンポーネントが v-model と動作します
input: function (event) {
vm.$emit('input', event.target.value)
}
}
)
}
},
template: `
<label>
{{ label }}
<input
v-bind="$attrs"
v-bind:value="value"
v-on="inputListeners"
>
</label>
`
})
<base-input>
コンポーネントが 完全に透過的なラッパ として扱えるようになったため、普通の <input>
要素と全く同じように使うことができるようになりました。.native
修飾子なしで全ての同じ要素とリスナが動作します。
.sync
修飾子
2.3.0から新規追加
“双方向バインディング”がプロパティに対して必要な場合もあります。残念ながら、本当の双方向バインディングはメンテナンスの問題を引き起こす可能性があります。子コンポーネントは親でも子でもその変更元が明らかでなくても親を変更させることができるからです。
このため代わりに update:myPropName
というパターンでイベントを発火させる事をお薦めします。例えば title
というプロパティを持つ仮のコンポーネントがあった場合、意図的に新しい値を割り当てる事ができます
this.$emit('update:title', newTitle)
こうする事で、必要な場合、親がこのイベントを購読し、ローカルデータプロパティを更新することができます。例えば:
<text-document
v-bind:title="doc.title"
v-on:update:title="doc.title = $event"
></text-document>
このパターンを .sync
修飾子で短く書くことができます:
<text-document v-bind:title.sync="doc.title"></text-document>
v-bind
に .sync
修飾子をつける場合は式を指定しても動作しないことに注意してください (例: v-bind:title.sync=”doc.title + ‘!’”
は無効です)。そうではなく、 v-model
と同様にバインドしたいプロパティ名のみを指定してください。
.sync
修飾子を v-bind
に付けることでオブジェクトを使って複数のプロパティを一度にセットする事ができます:
<text-document v-bind.sync="doc"></text-document>
こうする事で doc
オブジェクト内の各プロパティ (例えば title
) がひとつのプロパティとして渡され、v-on
アップデートリスナがそれぞれに付けられます。
v-bind.sync
をv-bind.sync=”{ title: doc.title }”
などの様に文字列オブジェクトと一緒に使う場合、こういった複雑な表現をパースする際に様々なケースが考えられるのでうまく動作しません。