0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Vue.jsを1から学んでみた〜カスタムディレクティブ〜

Last updated at Posted at 2020-08-13

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>

結果
aaa22.gif

簡単な例(ローカル登録)

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>

結果
aaa22.gif

フック関数

カスタムディレクティブには、(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}となる。
  • 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>

結果
image.png

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>

結果
image.png

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>

結果
image.png

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>

結果:dottedがinputに反映される
image.png

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>

結果
image.png

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?