# カスタムディレクティブ
breaking

# 概要

コンポーネントのライフサイクルに合わせて、ディレクティブのフック関数の名称が変更されました。

加えて、expression 文字列は binding オブジェクトの一部として渡されなくなりました。

# 2.x での構文

Vue 2 では、以下のフックを使用して要素のライフサイクルをターゲットにしたカスタムディレクティブが作成していました。これらはすべてオプションです。

  • bind - ディレクティブが要素にバインドされると呼び出されます。これは一度だけ呼び出されます。
  • inserted - 要素が親 DOM に挿入された後に呼び出されます。
  • update - 要素が更新されたときに呼び出されますが、子はまだ更新されていません。
  • componentUpdated - コンポーネントと子が更新されると呼び出されます。
  • unbind - ディレクティブが削除されると呼び出されます。 また、これは一度だけ呼び出されます。

この例を次に示します。

<p v-highlight="'yellow'">このテキストを明るい黄色で強調表示します</p>
1
Vue.directive('highlight', {
  bind(el, binding, vnode) {
    el.style.background = binding.value
  }
})
1
2
3
4
5

この要素の初期設定では、ディレクティブは値を渡してスタイルをバインドします。値は、アプリケーションにてさまざまな値に更新できます。

# 3.x での構文

ただし、Vue 3 では、カスタムディレクティブ用のよりまとまりのある API を作成しました。Vue 2 では、似たようなイベントにフックしているにもかかわらず、コンポーネントのライフサイクルメソッドとは大きく異なります。これらを次のように統合しました。

  • created - 追加されました!これは、要素の属性やイベントリスナーが適用される前に呼び出されます。
  • bind → beforeMount
  • inserted → mounted
  • beforeUpdate: 追加されました!これは、コンポーネントのライフサイクルフックのように、要素自体が更新される前に呼び出されます。
  • update → 削除されました! updated と似たようなものが多すぎて冗長です。代わりに updated を使ってください。
  • componentUpdated → updated
  • beforeUnmount: 追加されました!コンポーネントのライフサイクルフックと同様に、要素がマウント解除される直前に呼び出されます。
  • unbind -> unmounted

最終的な API は次のとおりです。

const MyDirective = {
  created(el, binding, vnode, prevVnode) {}, // new
  beforeMount() {},
  mounted() {},
  beforeUpdate() {}, // 追加
  updated() {},
  beforeUnmount() {}, // 追加
  unmounted() {}
}
1
2
3
4
5
6
7
8
9

Vue 3 の API は、先ほどの例を用いてこのように使用できます。

<p v-highlight="'yellow'">このテキストを明るい黄色で強調表示します</p>
1
const app = Vue.createApp({})

app.directive('highlight', {
  beforeMount(el, binding, vnode) {
    el.style.background = binding.value
  }
})
1
2
3
4
5
6
7

カスタムディレクティブのライフサイクルフックがコンポーネントと同じになったことで、理由を説明したり、覚えるのがより簡単になりました。

# 特別な問題への対処: コンポーネントのインスタンスへのアクセス

一般的には、ディレクティブをコンポーネントのインスタンスから独立させることが推奨されています。カスタムディレクティブ内からインスタンスにアクセスする状況は、本来はディレクティブがコンポーネント自体であるべきことが多いです。しかし、まれにこれが有効なこともあります。

Vue 2 では、コンポーネントインスタンスは vnode 引数を使ってアクセスする必要がありました。

bind(el, binding, vnode) {
  const vm = vnode.context
}
1
2
3

Vue 3 では、インスタンスは binding の一部になりました。

mounted(el, binding, vnode) {
  const vm = binding.instance
}
1
2
3

WARNING

fragments のサポートにより、コンポーネントは複数のルートノードを持つ可能性があります。マルチルートコンポーネントに適用すると、カスタムディレクティブは無視され、警告がログ出力されます。

# 移行の戦略

移行ビルドのフラグ: CUSTOM_DIR