vue组件中实现鼠标右键弹出自定义菜单栏

目录

一、背景

二、步骤分析

2.1、监听鼠标右键事件

2.2、自定义弹出框

三、实现效果


一、背景

最近在写一个聊天程序,要实现点击鼠标右键弹出相关的操作菜单栏,以实现相关功能的拓展。这里主要是记录下,如何在vue项目中实现这种功能。

二、步骤分析

2.1、监听鼠标右键事件

首先,我们需要阻止原默认的鼠标右键事件,弹出我们自定义的相关菜单。这里想到可以使用JavaScript的dom监听器来实现此功能。

javascript 复制代码
// 监听快捷键事件,回调参数事件event
onMounted(
  () => {
    document.addEventListener('contextmenu', clickRightMouse)
  }
)

onUnmounted(
  () => {
    document.removeEventListener('contextmenu', clickRightMouse)
  }
)

// 鼠标右键监听
function clickRightMouse(event){
    // 阻止默认事件触发
    event.preventDefault();

    // 编写触发自定义逻辑
}

后面从网上查询了相关资料,发现vue有简写的语法糖,等效使用JavaScript监听器实现的功能实现。

html 复制代码
<!-- @contextmenu vue语法糖等效JavaScript对应的监听器 -->
<!-- .prevent vue事件修饰符,自动阻止默认事件运行 -->
<!-- handleRightClick 自定义事件运行逻辑 -->
<div @contextmenu.prevent="handleRightClick"></div>

2.2、自定义弹出框

点击鼠标右键,在光标所在位置的右侧弹出操作菜单,点击操作按钮,实现对应的操作逻辑。这里重要的是要在弹出框出现前,计算出弹出层的宽高位置。弹出框可以使用position: fiexd; 配合事件回调取出光标位置。

html 复制代码
<template>
    <div class="contactGroupList" @contextmenu.prevent="openMenu">
        <!-- 动态菜单 -->
        <teleport to=".contactGroupList" :defer="true">
          <div
            v-show="isShowMenu"
            class="context-menu"
            :style="{ top: `${mousePosition.y}px`, left: `${mousePosition.x}px` }"
          >
            <ul>
              <li @click="handleAction('addGroup')">
                <el-icon><Plus /></el-icon>添加分组
              </li>
              <li @click="handleAction('deleteGroup')">
                <el-icon><DeleteFilled /></el-icon>删除分组
              </li>
              <li @click="handleAction('manageGroup')">
                <el-icon><EditPen /></el-icon>重命名分组
              </li>
            </ul>
          </div>
        </teleport>
    <div>
</template>


<script setup>
import { ref, reactive, markRaw, onBeforeMount, watch } from 'vue'


// 右键打开自定义菜单
const isShowMenu = ref(false)
const mousePosition = ref({ x: 0, y: 0 })

const openMenu = (e) => {
  mousePosition.value = {
    x: e.clientX,
    y: e.clientY,
  }
  isShowMenu.value = true
  document.addEventListener('click', closeMenu)
}

const closeMenu = () => {
  isShowMenu.value = false
  document.removeEventListener('click', closeMenu)
}

const handleAction = (action) => {
  alert(`执行操作:${action}`)
  closeMenu()
}
</script>

<style lang='scss' scoped>
.contactGroupList {
    width: 100%;
    height: 100%:
    display: flex;
    flex-direction: column;

    // 联系人鼠标右键弹出菜单样式(弹出框挂载在contactList下的)
    .context-menu {
      position: fixed;
      background: white;
      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
      border-radius: 4px;
      z-index: 1000;
      font-size: 14px;
    }
    .context-menu ul {
      list-style: none;
      padding: 0;
      margin: 0;
      min-width: 120px;
    }
    .context-menu li {
      padding: 8px 12px;
      cursor: pointer;
      line-height: 100%;
      display: flex;
      flex-direction: row;
      gap: 5px;
    }
    .context-menu li:hover {
      background: #f5f5f5;
    }
}
</style>

三、实现效果

相关推荐
前端一小卒4 分钟前
搜索 API 额度用完返回空数组,Agent 就开始一本正经地胡说
前端·javascript·node.js
ljt272496066112 分钟前
Vue笔记(十三)--mixin
vue.js·笔记
w2sfot27 分钟前
AI时代,JS加密还有效吗?
开发语言·前端·javascript
haluhalu.41 分钟前
Agent = LLM + 上下文 + 工具(含观察 / 动作空间、ReAct 循环)
前端·javascript·人工智能·python·react.js·机器学习·个人开发
子兮曰6 小时前
把 649 种文件格式塞进一个网页里:一个「文件不出浏览器」的预览器
前端·javascript·后端
paopaokaka_luck9 小时前
基于springboot+vue的智慧家政管理系统(AI问答、 WebSocket实时沟通、ECharts运营分析、订单规则与服务追踪)
java·javascript·spring boot·数据分析·echarts·mybatis
溪语流沙10 小时前
【每天一个CSS | Day19】流光文字与一笔写成的手写签名
前端·javascript·css
CDwenhuohuo11 小时前
electron pc项目打包成桌面端
前端·javascript·electron
计算机毕设定制辅导-无忧学长13 小时前
《校园食堂在线订餐小程序的设计与实现》
java·vue.js·spring boot·微信小程序·uniapp·校园食堂在线订餐小程序
EatFan13 小时前
React 项目踩坑实录:useEffect 闭包陷阱、Context 性能陷阱与 React 18 升级避坑排查手册
前端·javascript·react.js·react·react hooks·useeffect·闭包陷阱