基礎からメモ: Vue.js CH4-p137 カスタムディレクティブでデータを監視しながらDOMを操作する
カスタムディレクティブの仕組みを使って、v-bind
のようなディレクティブを自作することができる。
ただしデータバインディングと違い仮想DOMではないので、$el
や$refs
と同様に描画の最適化はされない。
使い方
カスタムディレクティブとしてメソッドを登録し、そのメソッド名にv-
プレフィクスを付けてHTMLの中に使用する。
<div v-directive>example</div>
このカスタムディレクティブを呼び出すためのトリガーを値としてバインドすることもできる。次の場合は、value
が変化すると呼び出される。
<div v-directive="value">example</div>
ローカルへの登録
コンポーネントのdirectives
オプションに登録すると、特定のコンポーネント内でのみ使える。
<div id="app"> <input v-focus type="text"> </div>
この例では input要素にカスタムディレクティブv-focus
が結び付けられているので、input要素がDOMに挿入されるときフォーカスが当てられる。
var app = new Vue({ el: '#app', directives: { // 紐付いている要素(この場合はinput要素)がDOMに挿入されるとき // その要素にフォーカスを当てる focus: { inserted: function(el) { el.focus(); } } } })
グローバルへの登録
グローバルメソッドVue.directive
を使ってグローバルに登録されたカスタムディレクティブは、全てのコンポーネントから使える。
Vue.directive('focus', { inserted: function(el) { el.focus(); } })
使用可能なフック
メソッド名 | タイミング |
---|---|
bind | ディレクティブがはじめて要素と紐付いたとき |
inserted | 紐付いた要素が親Nodeに挿入されたとき |
update | 紐付いた要素を包含するコンポーネントのVNodeが更新されたとき |
componentUpdated | 包含するコンポーネントと子コンポーネントのVNodeが更新されたとき |
unbind | 紐付いている要素からディレクティブが削除されるとき |
update
とcomponentUpdated
は、コンポーネントの仮想DOMが更新されたときに呼び出されるので、どこにもデータバインディングしていないデータが変化しても呼び出されることはない。
フックの引数
引数 | 内容 |
---|---|
el | ディレクティブが付与されている要素 |
binding | バインドされた値、引数、修飾子のオブジェクト |
vnode | 要素に対応するVNode |
oldVnode | 更新前のVNode(update とcomponentUpdated のみで使える) |
フックの関数による省略記法
第二引数に関数を渡すと、bind
とupdate
にフックし、その処理を呼び出す。
Vue.directive('example', function(el, binding, vnode, oldVnode) { // bind と update で呼び出される処理 })
動画の再生をコントロールするサンプル
<div id="app"> <!-- 動画の再生をコントロールする --> <!-- 動画1 --> <button v-on:click="video1=true">再生</button> <button v-on:click="video1=false">停止</button> <video src="movie1.mp4" v-video="video1"></video> <!-- 動画2 --> <button v-on:click="video2=true">再生</button> <button v-on:click="video2=false">停止</button> <video src="movie2.mp4" v-video="video2"></video> </div>
var app = new Vue({ el: '#app', data: { video1: false, video2: false }, directives: { video(el, binding) { if (binding.value !== binding.oldValue) { binding.value ? el.play() : el.pause(); } } } })