Vue.jsで要素外クリックを検知するディレクティブを作る

投稿日 最終更新日

2024年11月26日

最近はAlpine.jsでなくVueを弄っている。
Alpine.jsには@click.outsideという便利メソッドがあるんだけど、Vueにはなかった。

無くて困っていたところ、自分でディレクティブを作る方法で上手くいったので残す。

独自ディレクティブを定義する

私はLaravel環境でVueを使っているので、resources/js/Directives/clickOutSide.jsと作成。

中身は以下のようにする。

export default {
    beforeMount(el, binding) {
        el.clickOutsideEvent = (event) => {
            if (!(el === event.target || el.contains(event.target))) {
                binding.value();
            }
        };
        document.addEventListener("click", el.clickOutsideEvent);
    },
    unmounted(el) {
        document.removeEventListener("click", el.clickOutsideEvent);
    },
};

beforeMount()やunmounted()は公式ドキュメントにある通り、要素が作成されたり削除されたりしたときに呼び出されるフック。

各フックの引数elはディレクティブが付いている要素自身を示し、binding.valueはディレクティブに渡される値を示す。

つまり、v-click-outside="() => console.log('クリック')"とすればbinding.valueはアロー関数となり、binding.value()で実行される感じ。

カスタムディレクティブをグローバルで登録する

続いて、先に作ったカスタムディレクティブをVueに登録する。

これはVueのアプリケーションインスタンスを作るときに登録してあげればおk。

import clickOutside from "@/Directives/clickOutside";

const app = createApp({})

app.directive("click-outside", clickOutside)

作ったclick-outsideを使ってみる

グローバルレベルで登録しているので、いきなり使ってしまって問題ない。
利用するときはv-[ディレクティブ名]で利用する。

<script setup>
const hi = () => {
  console.log("こんにちは!");
}
</script>

<template>
  <div v-clicl-outside="hi">
    要素内
  </div>
</template>

これでdivの外側をクリックするとコンソールに出力されるのが確認できると思う。

以上です。