【无标题】 一个鼠标右键插槽的菜单

这篇博客介绍了如何使用Vue创建一个右键菜单组件,包括组件代码、指令的定义和使用。组件通过接收props来定位菜单,并通过自定义指令`v-clickoutside`实现点击外部关闭菜单的功能。同时,文章展示了菜单的样式设置和过渡动画效果,以及在不同位置的智能调整。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一个鼠标右键插槽的菜单

组件代码

<template>
  <transition :name="transitionName">
    <div
      class="gi-content-menu"
      ref="contentMenu"
      :style="[contentMenuStyle]"
      v-show="getShow"
      v-clickoutside="handleClose"
    >
      <slot></slot>
    </div>
  </transition>
</template>

<script>
export default {
  name: 'GiContentMenu', // 右键菜单弹窗
  props: {
    value: {
      type: Boolean,
      default: false
    },
    axis: {
      type: Object,
      default: () => {}
    },
    width: {
      type: String,
      default: '100px'
    },
    height: {
      type: String,
      default: 'auto'
    }
  },
  data() {
    return {
      transitionName: '', // 过渡动画
      contentMenuHeight: 0,
      contentMenuStyle: {}
    }
  },
  watch: {
    'axis.x'() {
      this.$nextTick(() => {
        this.getShow = false
        setTimeout(async () => {
          this.getStyle()
          this.getShow = true
        }, 0)
      })
    },
    'axis.y'() {
      this.$nextTick(() => {
        this.contentMenuHeight = this.$refs['contentMenu'].offsetHeight
        this.transitionName =
          this.axis.y > window.innerHeight - this.contentMenuHeight ? 'el-zoom-in-bottom' : 'el-zoom-in-top'

        this.getShow = false
        setTimeout(() => {
          this.getStyle()
          this.getShow = true
        }, 0)
      })
    }
  },
  computed: {
    getShow: {
      get() {
        return this.value
      },
      set(val) {
        this.$emit('input', val)
      }
    }
  },
  methods: {
    getStyle() {
      // console.log('window.innerHeight', window.innerHeight)
      // console.log('this.axis.x', this.axis.x)
      // console.log('this.axis.y', this.axis.y)
      // console.log('contentMenuHeight', this.contentMenuHeight)
      const obj = {}
      obj.left = this.axis.x + 2 + 'px'
      if (this.axis.y > window.innerHeight - this.contentMenuHeight) {
        obj.bottom = window.innerHeight - this.axis.y + 'px'
      } else {
        obj.top = this.axis.y + 2 + 'px'
      }
      obj.width = this.width
      obj.height = this.height
      obj['z-index'] = 999
      this.contentMenuStyle = obj
    },
    handleClose() {
      this.$emit('input', false)
    }
  }
}
</script>

<style lang="scss" scoped>
.gi-content-menu {
  background: #fff;
  position: fixed;
  z-index: -999;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12), 0 0 6px rgba(0, 0, 0, 0.04);
  border-radius: 4px;
}
</style>


组件所用指令

import Vue from 'vue'
Vue.directive('clickoutside', {
  // 初始化指令
  bind(el, binding, vnode) {
    function documentHandler(e) {
      // 这里判断点击的元素是否是本身,是本身,则返回
      if (el.contains(e.target)) {
        return false
      }
      // 判断指令中是否绑定了函数
      if (binding.expression) {
        // 如果绑定了函数 则调用那个函数,此处binding.value就是handleClose方法
        binding.value(e)
      }
    }
    // 给当前元素绑定个私有变量,方便在unbind中可以解除事件监听
    el.__vueClickOutside__ = documentHandler
    document.addEventListener('click', documentHandler)
  },
  update() {},
  unbind(el, binding) {
    // 解除事件监听
    document.removeEventListener('click', el.__vueClickOutside__)
    delete el.__vueClickOutside__
  }
})

使用

<GiContentMenu :axis="axis" v-model="showContentMenu">
 <div>
     <section>新增</section>
     <section>编辑</section>
     <section>重命名</section>
     <section>删除</section>
 </div>
<GiContentMenu>

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值