vue-click-outside

Vue

特定の要素外がクリックされた際に、イベントのハンドリングができる vue-click-outside の実装方法です。
どんな場面で使えるのか、今回はボタンが押された時にメニューを表示させる機能を実装しながら vue-click-outside を使ってみたいと思います。

# インストール

npmもしくはyarnで vue-click-outside をインストールします。

npm install vue-click-outside
// or
yarn add vue-click-outside

# トグルメニュー

vue-click-outside を使う前の準備として、トグルメニューを実装してみます。
以下、サンプルコードと実際のトグルメニューになります。ボタンをクリックするとメニューの表示/非表示が切り替えられるのが確認できるかと思います。

# コード

CODE
<template>
  <div class="vue-click-outside">
    <span class="button" @click.stop="toggleMenu">
      Toggle Menu
    </span>
    <transition name="fade">
      <ul v-show="isOpen" class="menu">
        <li class="menu__item">hoge</li>
        <li class="menu__item">fuga</li>
        <li class="menu__item">piyo</li>
      </ul>
    </transition>
  </div>
</template>

<script>
export default {
  data() {
    return {
      isOpen: false
    };
  },
  methods: {
    toggleMenu() {
      this.isOpen = !this.isOpen;
    }
  }
};
</script>

<style lang="stylus" scoped>
.vue-click-outside
  position relative
  display inline-block
  .button
    padding 4px 16px 6px
    border 1px solid #cfcfcf
    border-radius 4px
    color #fff
    background-color #101010
    cursor pointer


  .menu
    position absolute
    top 8px
    right -208px
    z-index 10
    width 200px
    padding 0
    border 1px solid #dfdfdf
    border-radius 4px
    box-shadow 4px 4px 12px #cfcfcf
    background-color #fff
    list-style none
    &__item
      padding 8px
      border-bottom 1px solid #dfdfdf
      &last-child
        border-bottom none

.fade-enter-active,
.fade-leave-active
  transition opacity 0.5s

.fade-enter,
.fade-leave-to
  opacity 0
</style>

# プレビュー


Toggle Menu


ただ、一度表示されたメニューを非表示にするには、この実装では再度ボタンを押さないといけません。メニューが表示されたままページ内で他のアクションをされるのはちょっと嫌ですよね。自力でハンドリングするのも面倒。。。ってことで、ここで先程インストールした vue-click-outside を使います。

# 実装

先程実装したトグルメニューに vue-click-outside を使って、メニューが表示されている時にメニュー要素以外がクリックされた場合にメニューを非表示にする機能を実装します。
vue-click-outside をimportし、カスタムディレクティブを登録します。以下コードのハイライト部分を追記。


 
 
 
 
 





<script>
import ClickOutside from "vue-click-outside";
export default {
  directives: {
    ClickOutside
  },
  data() {

      ...
</script>

次に、要素外がクリックされた場合にイベントハンドリングしたい要素に v-click-outside="myHandlMethod"を記述します。今回はメニューの要素外がクリックされた際に、メニューを非表示にしたいので、先程のコードの<ul v-show="isOpen" class="menu">部分にv-click-outside="hideMenu"を追記し、メソッドを追加します。





 












 
 
 



<template>

  ・・・

  <ul v-show="isOpen" class="menu" v-click-outside="hideMenu">
    <li class="menu__item">hoge</li>
    <li class="menu__item">fuga</li>
    <li class="menu__item">piyo</li>
  </ul>

  ・・・
</template>

<script>
  ・・・
  methods: {
    ・・・
    hideMenu() {
      this.isOpen = false;
    }
  }
</script>

これで vue-click-outside の実装が完了しました。
v-click-outside部分のメソッドはメニューを非表示にするだけならtoggleMenuメソッドを使ってもいいのですが、要素外がクリックされた際にイベントハンドリングできるという意味で敢えて分けてみました。

# サンプル

以下、最終的はコードとプレビューになります。
実際には UI フレームワーク等を使っていると、トグルメニューを一から実装するなんてことは少ないかと思いますが、特定の要素外が押された場合になにかをしたいという場面では、実装も簡単なのでかなり使いやすいと思いました。

# コード

CODE
<template>
  <div class="vue-click-outside">
    <span class="button" @click.stop="toggleMenu">
      Toggle Menu
    </span>
    <transition name="fade">
      <ul v-show="isOpen" class="menu" v-click-outside="hideMenu">
        <li class="menu__item">hoge</li>
        <li class="menu__item">fuga</li>
        <li class="menu__item">piyo</li>
      </ul>
    </transition>
  </div>
</template>

<script>
import ClickOutside from "vue-click-outside";
export default {
  directives: {
    ClickOutside
  },
  data() {
    return {
      isOpen: false
    };
  },
  methods: {
    toggleMenu() {
      this.isOpen = !this.isOpen;
    },
    hideMenu() {
      this.isOpen = false;
    }
  }
};
</script>

<style lang="stylus" scoped>
.vue-click-outside
  position relative
  display inline-block
  .button
    padding 4px 16px 6px
    border 1px solid #cfcfcf
    border-radius 4px
    color #fff
    background-color #101010
    cursor pointer


  .menu
    position absolute
    top 8px
    right -208px
    z-index 10
    width 200px
    padding 0
    border 1px solid #dfdfdf
    border-radius 4px
    box-shadow 4px 4px 12px #cfcfcf
    background-color #fff
    list-style none
    &__item
      padding 8px
      border-bottom 1px solid #dfdfdf
      &last-child
        border-bottom none

.fade-enter-active,
.fade-leave-active
  transition opacity 0.5s

.fade-enter,
.fade-leave-to
  opacity 0
</style>

# プレビュー


Toggle Menu
Last Updated: 2021-9-2 12:36:29