特定の要素外がクリックされた際に、イベントのハンドリングができる 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 を使う前の準備として、トグルメニューを実装してみます。
以下、サンプルコードと実際のトグルメニューになります。ボタンをクリックするとメニューの表示/非表示が切り替えられるのが確認できるかと思います。
<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>
ただ、一度表示されたメニューを非表示にするには、この実装では再度ボタンを押さないといけません。メニューが表示されたままページ内で他のアクションをされるのはちょっと嫌ですよね。自力でハンドリングするのも面倒。。。ってことで、ここで先程インストールした 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 フレームワーク等を使っていると、トグルメニューを一から実装するなんてことは少ないかと思いますが、特定の要素外が押された場合になにかをしたいという場面では、実装も簡単なのでかなり使いやすいと思いました。
<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>