Клик вне элемента

08 Апреля 2022 02:04

Директива для обработки клика вне элемента. Например, чтобы закрывать модальные окна не на кнопку, а кликом за пределы модального окна.

Через директиву

Зарегистрировать глобально на весь проект

createApp(App)
  .directive("click-outside", {
    beforeMount(el, binding, vnode) {
      el.clickOutsideEvent = function(event) {
        if (!(el === event.target || el.contains(event.target))) {
          binding.value(event, el);
        }
      };
      document.body.addEventListener('click', el.clickOutsideEvent);
    },
    unmounted(el) {
      document.body.removeEventListener('click', el.clickOutsideEvent);
    }
  })
  .use(store)
  .use(router)
  .mount('#app')

Использование

<div v-click-outside='someMethod'></div>

Через метод

HTML

 <div id="app">
  <span class="greet" @click="showMenu=!showMenu" ref="dropdown">
    Hi Dummy
    <i class="fa fa-angle-down"></i>
    <ul class="user-menu" v-show="showMenu">
      <li>
        <i class="fa fa-edit"></i>
        Profile
      </li>
      <li>
        <i class="fa fa-sign-out"></i>
        Sign Out
      </li>
    </ul>
  </span>
</div>

JS

new Vue({
  el: '#app',
  data:{
    showMenu: false
  },
  created(){ 
    document.addEventListener('click', this.dropdown)
  },
  destroyed () {
    document.removeEventListener('click', this.dropdown)
  }, 
  methods:{
    dropdown(e){
      let el = this.$refs.dropdown;
      let target = e.target;
      if (el !== target && !el.contains(target)){
        this.showMenu = false
      }
    } 
  }
});

CSS

.greet{
  position: relative;
  float: right;
  margin-left: 10px;
  margin-right: 24px;
  cursor: pointer;
  color: #383838;
  font-size: 16px;
  line-height: 70px;
}
.user-menu{
  position: absolute;
  background: #fff;
  box-shadow: 0 7px 21px 0 rgba(0,0,0,0.1);
  list-style: none;
  top: 55px;
  right: -60px;
  width: 300px;
  text-align: left;
  padding-left: 0;
}
.user-menu li i{
  vertical-align: middle;
  margin-left: 35px;
  margin-right: 15px;
}