え、意外とみんな知らない！？要素外でクリックしたときにイベントを発火させる方法

皆さんこんにちは！

今サイト制作を行っている際に、ふとドロップダウンメニュー（プルダウンとも呼ぶ）を作っていた時、「要素外でクリックしたときにメニューを閉じたいな～」と思い、１から構築しようとしたけどめちゃだるい！！！

僕がサイト制作を行うときに一番心掛けていることは、「どれだけ楽をして作るか」を日々考えながらやっています。

そんな僕にとって、この機能を１から作るなんて死んでもやりたくもない。。。

Googleで検索したところ、、、

なんとありました！！

パッケージ名は「vue-click-outside」

初めて聞いた

さて、今回はドロップダウンメニューを作りつつ「vue-click-outside」を使っていきたいと思います。

使い方だけ見たいという方は、こちらの[サイト](https://www.npmjs.com/package/vue-click-outside)からご覧ください。

使い方の例も載っているので、分かりやすいかと。

それでは、順を追って一緒に使い方を見ていきましょう！

#パッケージのインストール#

```
npm i vue-click-outside --save-dev
```

#ドロップダウンメニューの作成（リストの作成）#

ここからはドロップダウンメニューを作っていきます。

表示したいメニュー項目を``menuList``で定義し、``isOpend``で要素をクリックしたかを判断します。また、``menuList``のプロパティはお好みで設定してください。

```App.vue
<script>
export default{
  data() {
    return {
      isOpend: false,
      menuList: [
        {
          icon: 'user',
          id: 'account?isActive=0',
          labelText: 'アカウント情報'
        },
        {
          icon: 'envelope',
          id: 'email?isActive=1',
          labelText: 'メールアドレス変更'
        },
        {
          icon: 'key',
          id: 'password?isActive=2',
          labelText: 'パスワード変更'
        },
        {
          icon: 'calendar-alt',
          id: 'event?isActive=3',
          labelText: 'イベント'
        },
        {
          icon: 'user-minus',
          id: 'withdrawal?isActive=4',
          labelText: '退会'
        }
      ]
    }
  },
}
</script>
```

#v-forでメニューリストを表示#

次は、先ほど作成したオブジェクトを使用し、v-forを使って表示していきます。

また、ドロップダウンメニューを表示したときモーダルウィンドウとして表示するため、Buefyを使っていきます。アイコンもBuefyで表示します。

Buefyの使い方は、こちら以下の記事で詳しく書いているので、興味のある方はぜひご覧ください！

[初心者必見！サイト制作は楽してなんぼ。CSSフレームワークBuefyの紹介！！](https://qiita.com/akki-memo/items/278ff2982961274955c4)
[効率的にサイト作り！Buefyでアイコンを表示しよう！！](https://qiita.com/akki-memo/items/1fa0d0a9ac6870ba9337)

```App.vue
<template>
  <div class="phone-side-menu">
    <div class="drop-down-menu">
      <div class="drop-down-menu-wrapper">
        <b-modal v-model="isOpend">
          <div class="drop-down-menu-list">
            <ul>
              <li v-for="(element, index) in menuList" :key="index">
                <input :id="element.id" name="sideMenuItems" type="radio" />
                <label :for="element.id" class="phone-menu-label">
                  <b-icon pack="fas" :icon="element.icon" size="medium"></b-icon>
                  {{ element.labelText }}
                </label>
              </li>
            </ul>
          </div>
        </b-modal>
      </div>
    </div>
  </div>
</template>
<script>
export default{
  data() {
    return {
      isOpend: false,
      menuList: [
        {
          icon: 'user',
          id: 'account?isActive=0',
          labelText: 'アカウント情報'
        },
        {
          icon: 'envelope',
          id: 'email?isActive=1',
          labelText: 'メールアドレス変更'
        },
        {
          icon: 'key',
          id: 'password?isActive=2',
          labelText: 'パスワード変更'
        },
        {
          icon: 'calendar-alt',
          id: 'event?isActive=3',
          labelText: 'イベント'
        },
        {
          icon: 'user-minus',
          id: 'withdrawal?isActive=4',
          labelText: '退会'
        }
      ]
    }
  },
}
</script>
```

#モーダルウィンドウの表示#

次は、クリックされたときにモーダルウィンドウを表示する関数、ボタンを作ります。

```App.vue
<template>
  <div class="phone-side-menu">
    <div class="drop-down-menu">
      <div class="drop-down-menu-wrapper">
        <!-- ここから追加  -->
        <b-button　type="is-text"　@click="toggleMenuList">
            ドロップダウンメニュー
        </b-button>
        <b-modal v-model="isOpend">
          <div class="drop-down-menu-list">
            <ul>
              <li v-for="(element, index) in menuList" :key="index">
                <input :id="element.id" name="sideMenuItems" type="radio" />
                <label :for="element.id" class="phone-menu-label">
                  <b-icon pack="fas" :icon="element.icon" size="medium"></b-icon>
                  {{ element.labelText }}
                </label>
              </li>
            </ul>
          </div>
        </b-modal>
      </div>
    </div>
  </div>
</template>
<script>
export default{
  data() {
    return {
      isOpend: false,
      menuList: [
        {
          icon: 'user',
          id: 'account?isActive=0',
          labelText: 'アカウント情報'
        },
        {
          icon: 'envelope',
          id: 'email?isActive=1',
          labelText: 'メールアドレス変更'
        },
        {
          icon: 'key',
          id: 'password?isActive=2',
          labelText: 'パスワード変更'
        },
        {
          icon: 'calendar-alt',
          id: 'event?isActive=3',
          labelText: 'イベント'
        },
        {
          icon: 'user-minus',
          id: 'withdrawal?isActive=4',
          labelText: '退会'
        }
      ]
    }
  },
  methods: {
    toggleMenuList() {
      this.isOpend = !this.isOpend
    }
}
</script>
```

ボタンをクリックしたら、``toggleMenuList``という関数を実行してモーダルウィンドウの表示・非表示を行います。

#要素外をクリックしたときの関数を作成#

最後に、モーダルウィンドウを表示中に要素外をクリックしたら、モーダルウィンドウを閉じるための関数を作成していきます。

関数名は``hideMenuList``、先ほどインストールしたパッケージをインストールしscript内で``directives``を定義、``v-click-outside``でイベントの発火

というような仕組みになっております。

```App.vue
<template>
  <!-- イベント発火 -->
  <div v-click-outside="hideMenuList" class="phone-side-menu">
    <div class="drop-down-menu">
      <div class="drop-down-menu-wrapper">
        <!-- ここから追加  -->
        <b-button　type="is-text"　@click="toggleMenuList">
            ドロップダウンメニュー
        </b-button>
        <b-modal v-model="isOpend">
          <div class="drop-down-menu-list">
            <ul>
              <li v-for="(element, index) in menuList" :key="index">
                <input :id="element.id" name="sideMenuItems" type="radio" />
                <label :for="element.id" class="phone-menu-label">
                  <b-icon pack="fas" :icon="element.icon" size="medium"></b-icon>
                  {{ element.labelText }}
                </label>
              </li>
            </ul>
          </div>
        </b-modal>
      </div>
    </div>
  </div>
</template>
<script>
export default{
  // ディレクティブを定義
  directives: {
    ClickOutside
  },
  data() {
    return {
      isOpend: false,
      menuList: [
        {
          icon: 'user',
          id: 'account?isActive=0',
          labelText: 'アカウント情報'
        },
        {
          icon: 'envelope',
          id: 'email?isActive=1',
          labelText: 'メールアドレス変更'
        },
        {
          icon: 'key',
          id: 'password?isActive=2',
          labelText: 'パスワード変更'
        },
        {
          icon: 'calendar-alt',
          id: 'event?isActive=3',
          labelText: 'イベント'
        },
        {
          icon: 'user-minus',
          id: 'withdrawal?isActive=4',
          labelText: '退会'
        }
      ]
    }
  },
  methods: {
    toggleMenuList() {
      this.isOpend = !this.isOpend
    },
    // 関数を定義
    hideMenuList() {
      this.isOpend = false
    }
}
</script>
```

いかがだったでしょうか？

このようにして、ドロップダウンメニューのモーダルウィンドウを表示、要素外をクリックしたらモーダルウィンドウを閉じるという一連の動作を完成させることができます！

最近、モチベが低下しつつある。。。

それでも僕は頑張ります！

皆さんも一緒に頑張りましょう！！！

以上、「え、意外とみんな知らない！？要素外でクリックしたときにイベントを発火させる方法」でした！

良かったら、LGTM、コメントお願いします。

また、何か間違っていることがあればご指摘頂けると幸いです。

他にも初心者さん向けに記事を投稿しているので、時間があれば他の記事も見て下さい！！

Thank you for reading