index.vue 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. <template>
  2. <div :style="style" v-show="show" @mousedown.stop @contextmenu.prevent>
  3. <slot></slot>
  4. </div>
  5. </template>
  6. <script setup>
  7. const props = defineProps({
  8. target: null,
  9. show: Boolean
  10. })
  11. const x = ref(null)
  12. const y = ref(null)
  13. const style = ref({})
  14. const binded = ref(false)
  15. const emit = defineEmits(['update:show', 'get-context-menu'])
  16. // 监听show的变化
  17. watch(
  18. () => props.show,
  19. (newValue) => {
  20. newValue ? bindHideEvents() : unbindHideEvents()
  21. }
  22. )
  23. watch(
  24. () => props.target,
  25. (newValue) => {
  26. bindEvents()
  27. }
  28. )
  29. // 初始化事件
  30. const bindEvents = (e) => {
  31. nextTick(() => {
  32. if (!props.target || binded.value) return
  33. props.target.addEventListener('contextmenu', contextMenuHandler)
  34. binded.value = true
  35. })
  36. }
  37. // 绑定隐藏菜单事件
  38. const bindHideEvents = () => {
  39. document.addEventListener('mousedown', clickDocumentHandler)
  40. document.addEventListener('mousewheel', clickDocumentHandler)
  41. }
  42. // 取消绑定隐藏菜单事件
  43. const unbindHideEvents = () => {
  44. document.removeEventListener('mousedown', clickDocumentHandler)
  45. document.removeEventListener('mousewheel', clickDocumentHandler)
  46. }
  47. // 鼠标按压事件处理器
  48. const clickDocumentHandler = () => {
  49. emit('update:show', false)
  50. }
  51. // 右键事件事件处理
  52. const contextMenuHandler = (e) => {
  53. x.value = e.clientX
  54. y.value = e.clientY
  55. layout()
  56. emit('update:show', true)
  57. emit('get-context-menu', e)
  58. e.preventDefault()
  59. }
  60. // 布局
  61. const layout = () => {
  62. style.value = {
  63. left: x.value + 'px',
  64. top: y.value + 'px',
  65. display: 'block'
  66. }
  67. }
  68. // 取消绑定事件
  69. const unbindEvents = () => {
  70. if (!props.target) return
  71. props.target.removeEventListener('contextmenu', contextMenuHandler)
  72. }
  73. </script>