首页 > 其他分享 >从零开始设计一个右键菜单组件

从零开始设计一个右键菜单组件

时间:2023-04-04 17:05:10浏览次数:54  
标签:菜单 const 自定义 menu item 从零开始 右键 ev

需求分析

首先要分析右键菜单需要实现什么功能

  • 点击鼠标右键弹出自定义的弹窗
  • 实现菜单项的点击
  • 自定义菜单项的样式
  • 自定义弹窗容器的样式

代码实现

需求搞定之后就是写代码了,下面是基础的代码框架

<template>
  <div class="yak-content-menu" @contextmenu="showContentMenuFn" @click="hideContextMenuFn">
    <slot></slot>
    <transition>
      <div
        v-show="visiable"
        class="yak-content-menu-wrap"
        :class="menuWrapClass"
        :style="{ left: menuPosition.left, top: menuPosition.top }"
      >
        <slot name="menu" :menuList="menus">
          <!-- 给于用户完整的菜单项控制权限 -->
          <span
            class="yak-content-menu-wrap-item"
            :class="menuItemClass"
            v-for="item in menus"
            :key="item.command"
            @click="menuClick(item)"
          >
            {{ item.text }}
          </span>
        </slot>
      </div>
    </transition>
  </div>
</template>
<script lang="ts">
import {
  ref,
  reactive,
  onMounted,
  onBeforeUnmount,
  defineComponent,
  PropType,
} from "vue";

interface MenuItem {
  command: string;
  text: string;
}

type Menus = Array<MenuItem>;

export default defineComponent({
  name: "YakContextmenu",
  props: {
    menus: {
      type: Array as PropType<Menus>,
      default: () => {
        return [];
      },
      required: true,
    }, // 菜单的数组
    menuWrapClass: String, // 菜单容器的自定义class
    menuItemClass: String, // 菜单项的自定义class
  },
  emits: ["menu-click"],
  setup(props, { emit }) {
    const wrapEl = ref();
    const visiable = ref(false);

    const menuPosition: any = reactive({
      left: 0,
      top: 0,
    });

    const showContextMenuFn = (ev: any) => {
      // 1:禁用默认的右键点击事件
      // 2:获取当前鼠标的位置
      // 3:控制弹窗的显示
    };

    const hideContextMenuFn = () => {
      // 隐藏菜单
    };

    const menuClick = (item: MenuItem) => {
      // 添加自定义事件 menu-click,方便组件使用
    };

    return {
      wrapEl,
      visiable,
      menuPosition,
      menuClick,
      showContentMenuFn,
      hideContextMenuFn,
    };
  },
});
</script>

实现 showContextMenuFn

有了上面的框架,现在让我们实现显示菜单的功能

const showContextMenuFn = (ev: any) => {
  // 禁用默认事件
  ev.preventDefault();
  // 获取自定义菜单的根元素的位置
  const rootPosition = wrapEl.value.getBoundingClientRect();
  // 用鼠标所在位置减去根元素的位置,就是弹窗元素相对于根元素的位置
  const x = ev.x - rootPosition.left;
  const y = ev.y - rootPosition.top;
  menuPosition.top = `${y}px`;
  menuPosition.left = `${x}px`;
  // 控制弹窗的显示
  visiable.value = true;
};

实现隐藏菜单和菜单点击

const hideContextMenuFn = () => {
  visiable.value = false; // 隐藏菜单
};

const menuClick = (item: MenuItem) => {
  emit("menu-click", item); // 添加自定义事件 menu-click
};

实现的效果

从零开始设计一个右键菜单组件_contextmenu

完整的代码

<template>
  <div class="yak-content-menu" @contextmenu="showContentMenuFn" @click="hideContextMenuFn">
    <slot></slot>
    <transition>
      <div
        v-show="visiable"
        class="yak-content-menu-wrap"
        :class="menuWrapClass"
        :style="{ left: menuPosition.left, top: menuPosition.top }"
      >
        <slot name="menu" :menuList="menus">
          <!-- 给于用户完整的菜单项控制权限 -->
          <span
            class="yak-content-menu-wrap-item"
            :class="menuItemClass"
            v-for="item in menus"
            :key="item.command"
            @click="menuClick(item)"
          >
            {{ item.text }}
          </span>
        </slot>
      </div>
    </transition>
  </div>
</template>
<script lang="ts">
import {
  ref,
  reactive,
  onMounted,
  onBeforeUnmount,
  defineComponent,
  PropType,
} from "vue";

interface MenuItem {
  command: string;
  text: string;
}

type Menus = Array<MenuItem>;

export default defineComponent({
  name: "YakContextmenu",
  props: {
    menus: {
      type: Array as PropType<Menus>,
      default: () => {
        return [];
      },
      required: true,
    }, // 菜单的数组
    menuWrapClass: String, // 菜单容器的自定义class
    menuItemClass: String, // 菜单项的自定义class
  },
  emits: ["menu-click"],
  setup(props, { emit }) {
    const wrapEl = ref();
    const visiable = ref(false);

    const menuPosition: any = reactive({
      left: 0,
      top: 0,
    });

    const showContextMenuFn = (ev: any) => {
      // 禁用默认事件
      ev.preventDefault();
      // 获取自定义菜单的根元素的位置
      const rootPosition = wrapEl.value.getBoundingClientRect();
      // 用鼠标所在位置减去根元素的位置,就是弹窗元素相对于根元素的位置
      const x = ev.x - rootPosition.left;
      const y = ev.y - rootPosition.top;
      menuPosition.top = `${y}px`;
      menuPosition.left = `${x}px`;
      // 控制弹窗的显示
      visiable.value = true;
    };

    const hideContextMenuFn = () => {
      visiable.value = false; // 隐藏菜单
    };

    const menuClick = (item: MenuItem) => {
      emit("menu-click", item); // 添加自定义事件 menu-click
    };

    return {
      wrapEl,
      visiable,
      menuPosition,
      menuClick,
      showContentMenuFn,
      hideContextMenuFn,
    };
  },
});
</script>
<style lang="scss">
.yak-content-menu {
  position: relative;
  &-wrap {
    display: inline-block;
    box-sizing: border-box;
    background-color: #fff;
    position: absolute;
    box-shadow: 0 1px 6px rgb(0 0 0 / 20%);
    border-color: 1px solid #eee;
    border-radius: 4px;
    padding: 5px 0;
    min-width: 160px;
    &-item {
      cursor: pointer;
      display: block;
      line-height: 28px;
      font-size: 14px;
      padding: 0 24px;
      text-align: left;
      &:hover {
        background-color: #eee;
      }
    }
  }
}

仓库地址 Github,如有需求,欢迎提交issue



标签:菜单,const,自定义,menu,item,从零开始,右键,ev
From: https://blog.51cto.com/jikun/6169044

相关文章

  • Gorm 实现无限树形菜单
    原文链接:https://www.zhoubotong.site/post/91.html通常树形菜单的实现基本就是递归调用,大部分场景毕竟这种数据不多,性能倒是并不突出,下面给个demo,有兴趣的朋友可以看看:新建一个city表:CREATETABLE`city`(`id`intNOTNULLAUTO_INCREMENT,`pid`intNOTNULLDEFA......
  • android下拉菜单 spinner 学习
    首先看一下继承关系:publicclassSpinnerextendsAbsSpinnerimplementsDialogInterface.OnClickListenerClassOverview视图在同一时间只能显示一个子项,用户通过下拉的方式可以选择其中的一种项。该子项在Spinner来自来Adpater视图适配器。首先看一下效果图:Spinner控件的使......
  • 从零开始USRP 02 一些基本的GNU Radio操作
    继续学习:https://blog.csdn.net/YOUNGAAAAA/article/details/128098154我们可以先简单创建一个USRP图:  但是这个图目前是跑不了的,因为:RuntimeError:LookupError:KeyError:Nodevicesfoundfor----->EmptyDeviceAddress>>>Done(returncode1)这里我暂时先不......
  • 全键盘模式,目前按center key 和LSK时候会进入menu 菜单,期望按center键进入编辑
    1.新增如下functrion: /******************************************************************************FUNCTION*jvm_dummy_key_hdlr*DESCRIPTION**PARAMETERS*void*RETURNS*void***************......
  • 成品直播源码推荐,Android 禁止下拉菜单栏
    成品直播源码推荐,Android禁止下拉菜单栏1.屏蔽非锁屏下的下拉菜单栏这种Android系统其实是提供了方法的,只不过是隐藏的,只给系统应用,也就是用mk编译的apk使用。如果第三方应用想要使用,或者Androidstuido编译方式的想要使用。则可以使用反射。 /** *Allowsanapptoco......
  • element树形复选框实现一级菜单单选
      <!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><metaname="viewport"content="width=d......
  • Win11右键菜单如何直接默认显示更多选项
    Win11右键菜单如何直接默认显示更多选项1、首先用鼠标右键点击“开始”按钮(或者按Win+X键),选择点击“Windows终端(管理员2、然后在终端应用程序里粘贴这串代码【reg.exeadd"HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32"/f/......
  • 将WebStorm添加到右键菜单,右键打开当前目录
    注意:软件每次更新之后,由于版本号发生了变动,需要我们手动再修改一遍。注册表编辑器计算机\HKEY_CLASSES_ROOT\Directory\Background\shellWebStorm文件夹见下图数值数据:C:\Users\Lemon\AppData\Local\JetBrains\Toolbox\apps\WebStorm\ch-0\222.3739.57\bin\webstorm64.......
  • 菜单1-3分析
    这三次菜单分析主要考察学生对于面对对象程序设计的理解,不同以往的是我们之前是面向过程,这毫无疑问会增加代码的复杂程度,而这次菜单计价系统则是主要考察我们面对对象程序设计能力,要求我们运用封装对象,对象之间的联系,类的调用和类的相互之间调用,总而言之,相对于c来说java的主函数......
  • 菜单计价程序1-3
    菜单计价程序-1一丶代码:1.菜品类点击查看代码classDish{Stringname;intunit_prince;intgetPrice(intportion){intpeic=0;switch(portion){case1:peic=(int)unit_prince;break;cas......