vue3+ts 封装右键菜单

377 阅读2分钟

介绍:

这个封装的右键菜单组件是一个 Vue 3 组件,使用了组合式 API 和 TypeScript。它允许在页面上显示一个自定义的右键菜单,并处理菜单项的点击事件。以下是对这个组件的详细解说:

模板部分:

<template name="contextmenu">
  <div v-show="visible" :style="style" class="context-menu">
    <ul>
      <li v-for="item in menuItems" :key="item.key" @click="handleClick(item)">
        <el-icon v-if="item.icon"><component :is="item.icon" /></el-icon>
        <span>{{ item.label }}</span>
      </li>
    </ul>
  </div>
</template>
  • v-show="visible":控制菜单的显示和隐藏。
  • :style="style":动态设置菜单的位置。
  • v-for="item in menuItems":遍历 menuItems 数组,生成菜单项。
  • @click="handleClick(item)":点击菜单项时调用 handleClick 方法。
  • <el-icon v-if="item.icon"><component :is="item.icon" /></el-icon>:如果菜单项有图标,则显示图标。

脚本部分:

<script setup lang="ts">
import { ref, computed } from 'vue'

interface MenuItem {
  key: string
  label: string
  icon?: string
  handler?: () => void
}

const props = defineProps<{
  menuItems: MenuItem[]
}>()

const visible = ref(false)
const position = ref({ x: 0, y: 0 })

const style = computed(() => ({
  left: position.value.x + 'px',
  top: position.value.y + 'px'
}))

const show = (e: MouseEvent) => {
  e.preventDefault()
  position.value = { x: e.clientX, y: e.clientY }
  visible.value = true

  // 点击其他地方关闭菜单
  document.addEventListener('click', hide)
}

const hide = () => {
  visible.value = false
  document.removeEventListener('click', hide)
}

const handleClick = (item: MenuItem) => {
  item.handler?.()
  hide()
}

// 暴露方法给父组件
defineExpose({ show, hide })
</script>
  • ref 和 computed:用于定义响应式数据和计算属性。
  • MenuItem 接口:定义菜单项的类型。
  • props:定义组件的 menuItems 属性。
  • visible:控制菜单的显示和隐藏。
  • position:存储菜单的位置。
  • style:计算菜单的位置样式。
  • show 方法:显示菜单,并设置菜单的位置。
  • hide 方法:隐藏菜单,并移除点击事件监听器。
  • handleClick 方法:处理菜单项的点击事件,调用菜单项的 handler 方法,并隐藏菜单。
  • defineExpose:暴露 show 和 hide 方法给父组件,以便父组件可以调用这些方法来显示和隐藏菜单。

样式部分:

<style lang="less" scoped>
.context-menu {
  position: fixed;
  z-index: 999;
  background: white;
  border: 1px solid @border-color;
  border-radius: 4px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);

  ul {
    list-style: none;
    padding: 5px 0;
    margin: 0;
  }

  li {
    padding: 8px 16px;
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 8px;

    &:hover {
      background-color: #f5f7fa;
    }
  }
}
</style>

使用组件:

<template>
  <div class="notes-wrapper">
    <div class="notes-container">
      <!-- Notes List -->
      <div class="notes-list">
        <div
          @contextmenu.prevent="showContextMenu"
        >
          <div class="note-content">选择1</div>
        </div>
      </div>
    </div>
    <ContxtMenu ref="contextMenuRef" :menu-items="menuItems" />
  </div>
</template>
<script lang="ts" setup>
import { ref, defineAsyncComponent } from 'vue'
// 组件引入
const ContxtMenu = defineAsyncComponent(() => import('@/components/contextmenu/index.vue'))
// 类型定义
interface MenuItem {
  key: string
  label: string
  icon: string
  handler: () => void
}

const contextMenuRef = ref()

// 自定义右键菜单配置
const menuItems: MenuItem[] = [
  {
    key: 'edit',
    label: '编辑',
    icon: 'Edit',
    handler: () => handleEdit()
  },
  {
    key: 'delete',
    label: '删除',
    icon: 'Delete',
    handler: () => handleDelete()
  }
]

// 事件处理方法
const showContextMenu = (e: MouseEvent) => {
  contextMenuRef.value?.show(e)
}


const handleEdit = () => {
  console.log('编辑')
}

const handleDelete = () => {
  console.log('删除')
}

</script>

@contextmenu.prevent 是 Vue.js 中的一个事件修饰符,用于监听右键菜单事件并阻止默认行为。具体来说:

  • @contextmenu:监听右键菜单事件。当用户在元素上点击鼠标右键时,会触发这个事件。
  • .prevent:Vue.js 的事件修饰符,用于调用 event.preventDefault() 方法,阻止浏览器的默认右键菜单弹出行为。

在你的代码中,@contextmenu.prevent="showContextMenu" 的作用是,当用户在 note-item 元素上点击右键时,阻止浏览器默认的右键菜单弹出,并调用 showContextMenu 方法来显示自定义的右键菜单。