varHarrie/varharrie.github.io

Vue.js用directive判断是否点击当前DOM以外的地方

varHarrie opened this issue · 2 comments

Vue 1.x

Vue.directive('clickOutside', {
  bind () {
    this.onClick = (event) => {
      if (this.el.contains(event.target)) return false
      if (this.expression) this.vm[this.expression]()
    }

    setTimeout(() => {
      document.addEventListener('click', this.onClick)
    })
  },
  unbind () {
    document.removeEventListener('click', this.onClick)
  }
})

Vue 2.x(来自评论)

Vue.directive('clickOutside', {
  bind (el, binding, vnode) {
    el.event = function (event) {
      if (!(el === event.target || el.contains(event.target))) {
        vnode.context[binding.expression](event)
      }
    }
    document.body.addEventListener('click', el.event)
  },
  unbind (el) {
    document.body.removeEventListener('click', el.event)
  }
})

Vue 3.x

<script>
const vClickOutside = {
  mounted(el, binding) {
    el.clickOutside = (e) => {
      if (el.contains(event.target)) return false
      if (typeof binding.value === 'function') binding.value(e)
    }

    document.addEventListener('click', el.clickOutside)
  },
  beforeUnmount(el) {
    document.removeEventListener('click', el.clickOutside)
  }
}

export default {
  directives: {
    clickOutside: vClickOutside,
  },
  methods: {
    log() {
      console.log('click')
    }
  }
}
</script>

<template>
  <div class="rect" v-click-outside="log">click outside</div>
</template>

<style>
  .rect {
    margin: 50px;
    padding: 12px;
		display: inline-block;
    border: 1px solid black;
    user-select: none;
  }
</style>

Get it.
Thx

Vue2.0 的自定义指令不再支持this引用,需要对其进行一定程度的改写。

// 自定义指令, 判断当前点击是否在DOM以外的地方
Vue.directive('clickOutside', {
  bind (el, binding, vnode) {
    el.event = function (event) {
      if (!(el === event.target || el.contains(event.target))) {
        // call method provided in attribute value
        vnode.context[binding.expression](event)
      }
    }
    document.body.addEventListener('click', el.event)
  },
  unbind (el) {
    document.body.removeEventListener('click', el.event)
  }
})