11-1 カスタムディレクティブとは
Vue.jsで用意してくれているディレクティブ(v-on
,v-bind
等)の他に、
自分で作成したディレクティブ(これがカスタムディレクティブ)を定義&使用できる。
簡単な例(グローバル登録)
画面が表示された時に最初にフォーカスされるv-focus
というカスタムディレクティブを定義、使用します。
main.js
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
// グローバル登録:カスタムディレクティブ
Vue.directive('focus', {
// フック関数
inserted: function (el) {
// ディレクティブフックに引数でelを渡し、
// 要素にフォーカスを当てる
el.focus()
}
})
new Vue({
render: h => h(App),
}).$mount('#app')
App.vue
<template>
<div>
<Job></Job>
</div>
</template>
<script>
import Job from "./components/Job.vue";
export default {
data: function() {
return {
defaultAge: 15,
defaultCheck: true
}
},
components: {
Job: Job
}
}
</script>
Job.vue
<template>
<div>
<p>私はエンジニアです</p>
<input type="checkbox">
<!-- こちらにフォーカスがあたる -->
<input type="text" v-focus>
</div>
</template>
簡単な例(ローカル登録)
main.js
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
App.vue
<template>
<div>
<Job></Job>
</div>
</template>
<script>
import Job from "./components/Job.vue";
export default {
data: function() {
return {
defaultAge: 15,
defaultCheck: true
}
},
components: {
Job: Job
}
}
</script>
Job.vue
<template>
<div>
<p>私はエンジニアです</p>
<input type="checkbox">
<!-- こちらにフォーカスがあたる -->
<input type="text" v-focus>
</div>
</template>
<script>
export default {
directives: {
// ローカル登録:カスタムディレクティブ
focus: {
inserted: function (el) {
// ディレクティブフックに引数でelを渡し、
// 要素にフォーカスを当てる
el.focus()
}
}
}
}
</script>
フック関数
カスタムディレクティブには、(Vueインスタンスのライフサイクルフックのような)用意された関数がある。
main.js
Vue.directive('focus', {
// bind(), inserted(), update(), componentUpdated(), unbind()
// 上記5つが用意されている。
bind(el, binding, vnode) {
// 画面が表示された時に1回だけ実行されるメソッド
},
inserted(el, binding, vnode) {
// 親Nodeに挿入された時に実行されるメソッド
},
update(el, binding, vnode, oldNode) {
// 子コンポーネントが更新される前に実行されるメソッド
},
componentUpdated(el, binding, vnode, oldNode) {
// 子コンポーネントが更新される後に実行されるメソッド
},
unbind(el, binding, vnode, oldNode) {
// ディレクティブが紐づいている要素から削除される時に1回だけ実行されるメソッド
}
})
ディレクティブフック引数
フック関数には、以下の引数を渡せる。
- el:ディレクティブのが紐づく要素。VNodeではなく、DOM要素を直接操作できる。
- binding:オブジェクト。以下のプロパティを持つ
- name:
v-
無しのディレクティブ名。v-focus
であればfocus
。 - value: ディレクティブに渡される値。
v-focus="'1+1'"
であれば1+1
という文字列。ダブルクォーテーション内はJavaScript式として判断されるため、文字列を指定する場合はシングルクォーテーションが必要。 - oldValue: update と componentUpdated においてのみ利用できる、更新前の値。
- expression: ディレクティブに渡される値を文字列として評価する。
v-focus="1+1"
は、valueの場合2
、expressionの場合1+1
となる。 - arg: ディレクティブに渡される引数。
v-focus:hoge
であればhoge
。一つしか設定できない。 - modifiers: 修飾子 (modifier) を含んでいるオブジェクト。設定された場合、trueが設定される。
v-focus:hoge.foo.zoo
の場合、{ foo: true, zoo: true}
となる。
- name:
- vnode:紐づくVNode=仮想ノード。
- oldValue:
update()
,componentUpdated()
のみで利用できる。変更前のVnode。
省略記法
実際のところ、フック関数はbind()
、update()
が多く使われる。
このため、Vue.jsは以下のような省略記法が用意される。
main.js
Vue.directive('color-swatch', function (el, binding) {
el.style.backgroundColor = binding.value
})
実際の開発でもほぼこれが使われるだろうと思う。
11-2 引数:el
elは、直接DOMを操作できる。
main.js
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
Vue.directive('color-swatch', function (el) {
// elを使い、背景色を赤色に。
el.style.backgroundColor = 'red'
})
new Vue({
render: h => h(App),
}).$mount('#app')
Job.vue
<template>
<div>
<p>私はエンジニアです</p>
<input type="text" v-color-swatch>
</div>
</template>
11-3 引数:binding
value(単一)
カスタムディレクティブに値を渡すことで、bindingに設定される
main.js
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
Vue.directive('color-swatch', function (el, binding) {
// カスタムディレクティブの
// bindingを使って背景色を変更する
el.style.backgroundColor = binding.value
})
new Vue({
render: h => h(App),
}).$mount('#app')
Job.vue
<template>
<div>
<p>私はエンジニアです</p>
<!-- 値を指定する。JavaScriptを指定するので文字列はシングルクォーテーション -->
<input type="text" v-color-swatch="'blue'">
</div>
</template>
value(複数)
カスタムディレクティブにオブジェクトを渡すことで、bindingに設定される
main.js
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
Vue.directive('color-swatch', function (el, binding) {
// オブジェクトのkeyを指定する
el.style.backgroundColor = binding.value.color
el.style.width = binding.value.width
})
new Vue({
render: h => h(App),
}).$mount('#app')
Job.vue
<template>
<div>
<p>私はエンジニアです</p>
<!-- 値を指定する。JavaScriptを指定するので文字列はシングルクォーテーション -->
<input type="text" v-color-swatch="{color: 'black', width: '15px'}">
</div>
</template>
arg
ディレクティブに渡される引数。v-focus:hoge
であればhoge
。一つしか設定できない。
main.js
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
Vue.directive('color-swatch', function (el, binding) {
el.style.backgroundColor = binding.value.color
el.style.width = binding.value.width
// .argで引数の文字列をそのまま取得できる
el.style.borderStyle = binding.arg
})
new Vue({
render: h => h(App),
}).$mount('#app')
Job.vue
<template>
<div>
<p>私はエンジニアです</p>
<!-- :dotted のように引数を指定する -->
<!-- 引数の指定は一つだけしか許可されていない -->
<input type="text" v-color-swatch:dotted="{color: 'white', width: '200px'}">
</div>
</template>
modifiers
修飾子 (modifier) を含んでいるオブジェクト。設定された場合、trueが設定される。v-focus:hoge.foo.zoo
の場合、{ foo: true, zoo: true}
となる。
main.js
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
Vue.directive('color-swatch', function (el, binding) {
el.style.backgroundColor = binding.value.color
el.style.width = binding.value.width
el.style.borderStyle = binding.arg
if (binding.modifiers.round) {
// modifirs.修飾子名で評価できる
el.style.borderRadius = "500rem"
}
})
new Vue({
render: h => h(App),
}).$mount('#app')
Job.vue
<template>
<div>
<p>私はエンジニアです</p>
<!-- .roundのように修飾子を指定する -->
<!-- 複数指定する場合は、:dotted.round.mount のように、.でつなげる -->
<input type="text" v-color-swatch:dotted.round="{color: 'white', width: '200px'}">
</div>
</template>