当前位置: 首页 > ops >正文

不想要网页默认的右键菜单栏,怎么封装一个可以自定义的右键菜单组件?

说在前面

🎈网页的功能和用途可能各不相同,在传统右键菜单栏中无法满足每个用户的个性化需求。通过自定义右键菜单栏,用户可以根据自己的需求添加、调整和删除菜单选项,以实现个性化定制。通过自定义右键菜单栏,可以为用户提供快速访问常用功能和操作的便捷方式,从而提高用户体验。

效果展示

实现原理

1、oncontextmenu事件了解一下

oncontextmenu 事件在元素中用户右击鼠标时触发并打开上下文菜单。

oncontextmenu是一个DOM事件,它在用户右键点击时触发。可以通过在HTML元素上添加oncontextmenu属性来指定右键菜单的处理函数。

例如,在一个按钮元素上添加oncontextmenu属性:

<button oncontextmenu="showContextMenu(event)">右键点击我</button>

在这个示例中,当用户右键点击按钮时,会调用showContextMenu函数,并将事件对象作为参数传递给该函数。

在JavaScript代码中,可以定义showContextMenu函数来处理右键菜单的显示和操作:

function showContextMenu(event) {event.preventDefault(); // 阻止默认的右键菜单弹出// 显示自定义右键菜单// ...
}

在showContextMenu函数中,通过调用event.preventDefault()方法阻止浏览器默认的右键菜单弹出。然后,可以根据需要执行自定义的逻辑,例如显示自定义的右键菜单。

2、在指定容器元素自定义右键菜单

首先,使用getElementById方法获取绑定右键菜单的DOM元素和右键菜单的容器元素。如果获取失败,则直接返回。

const dom = document.getElementById(this.domId);
if (!dom) return;

接着,给绑定右键菜单的DOM元素添加oncontextmenu事件处理函数。当用户触发右键点击事件时,首先调用hideAllMenu方法隐藏所有的右键菜单,然后通过event.preventDefault方法禁止默认行为,防止浏览器弹出默认的右键菜单。接下来,计算出鼠标指针相对于文档顶部和左侧的位置,并设置右键菜单的位置和显示状态。

const that = this;
dom.oncontextmenu = function (e) {that.hideAllMenu(that.uid);// 自定义body元素的鼠标事件处理函数e = e || window.event;e.preventDefault();let scrollTop =document.documentElement.scrollTop ||document.body.scrollTop; // 获取垂直滚动条位置let scrollLeft =document.documentElement.scrollLeft ||document.body.scrollLeft; // 获取水平滚动条位置menu.style.display = "block";menu.style.left = e.clientX + scrollLeft + "px";menu.style.top = e.clientY + scrollTop + "px";
};

最后,给document对象添加onclick事件处理函数。当用户在其他位置点击鼠标时,调用hideAllMenu方法隐藏所有的右键菜单。

document.onclick = function () {that.hideAllMenu();
};
hideAllMenu(id) {const jMenu = document.getElementsByClassName("j-mouse-menu");for (let i = 0; i < jMenu.length; i++) {if (jMenu[i].id != id) jMenu[i].style.display = "none";}
},

3、封装成一个组件

(1)template菜单模板
<div :id="uid" class="j-mouse-menu"><slot name="header"></slot><ul><liv-for="menuItem in menu":key="menuItem.id"@click="menuClick(menuItem)">{{ menuItem.label }}</li></ul><slot name="body"></slot><slot name="footer"></slot>
</div>

使用:id="uid"绑定了组件的id属性,该属性值由组件实例的uid属性提供。这样可以确保每个组件实例都有唯一的id。

然后,给组件添加了j-mouse-menu类,用于设置组件的样式。

在组件的内容区域中,使用了Vue的插槽机制。

  • <slot name="header"></slot>定义了一个名为"header"的插槽,用于放置菜单栏的头部内容。
  • <ul>标签下使用了v-for指令遍历menu数组,生成菜单项。
  • 菜单项使用<li>标签表示,并通过:key绑定了唯一的menuItem.id作为key值。
  • 通过@click绑定了menuClick方法,该方法会在点击菜单项时被调用。
  • 菜单项的显示文本使用插值语法{{ menuItem.label }}来动态显示。

接下来,又定义了两个插槽:

  • <slot name="body"></slot>用于放置菜单栏的主体内容。
  • <slot name="footer"></slot>用于放置菜单栏的底部内容。
(2)props入参
props: {domId: {type: String,default: "",},menu: {type: Array,default: () => {return [];},},
},

domId表示需要绑定右键菜单的DOM元素容器的id,menu表示右键菜单的选项列表,menu数据格式如下:

[{id: "1",label: "菜单1"},{id: "2",label: "菜单2",click: this.test},{id: "3",label: "菜单3"},{id: "4",label: "菜单4"},{id: "5",label: "菜单5"}
]
(3)菜单点击回调
menuClick(item) {if (item.click) {item.click(item);return;}this.$emit("menuClick", item);
},

首先判断item对象是否存在click属性。如果存在,则执行item.click(item),并将item作为参数传递给click函数。然后,返回结束方法的执行。

如果item对象不存在click属性,即没有自定义的点击处理函数,那么就通过this.$emit(“menuClick”, item)语法触发一个名为"menuClick"的自定义事件,并将item作为参数传递给父组件。

(4)完整组件代码
<template><div><div :id="uid" class="j-mouse-menu"><slot name="header"></slot><ul><liv-for="menuItem in menu":key="menuItem.id"@click="menuClick(menuItem)">{{ menuItem.label }}</li></ul><slot name="body"></slot><slot name="footer"></slot></div></div>
</template><script>
import { getUId } from "../../../utils/strTool";
export default {name: "JMouseMenu",props: {domId: {type: String,default: "",},menu: {type: Array,default: () => {return [];},},},data() {return {uid: "",};},created() {this.setUid();},mounted() {this.init();},methods: {setUid() {this.uid = "j-mouse-menu-" + getUId();},init() {// 自定义鼠标右键菜单栏const dom = document.getElementById(this.domId);if (!dom) return;const menu = document.getElementById(this.uid);const that = this;dom.oncontextmenu = function (e) {that.hideAllMenu(that.uid);// 自定义body元素的鼠标事件处理函数e = e || window.event;e.preventDefault();let scrollTop =document.documentElement.scrollTop ||document.body.scrollTop; // 获取垂直滚动条位置let scrollLeft =document.documentElement.scrollLeft ||document.body.scrollLeft; // 获取水平滚动条位置menu.style.display = "block";menu.style.left = e.clientX + scrollLeft + "px";menu.style.top = e.clientY + scrollTop + "px";};// 鼠标点击其他位置时隐藏菜单document.onclick = function () {that.hideAllMenu();};},hideAllMenu(id) {const jMenu = document.getElementsByClassName("j-mouse-menu");for (let i = 0; i < jMenu.length; i++) {if (jMenu[i].id != id) jMenu[i].style.display = "none";}},menuClick(item) {if (item.click) {item.click(item);return;}this.$emit("menuClick", item);},},
};
</script><style lang="less" scoped>
.j-mouse-menu {display: none;position: absolute;min-width: 8em;max-width: 15em;border: 1px solid #ccc;background: #eee;ul {margin: 5px 0;padding: 0;}li {height: 30px;line-height: 30px;color: #21232e;font-size: 12px;text-align: center;cursor: default;padding: 0;margin: 0;list-style-type: none;border-bottom: 1px dashed #cecece;&:hover {background-color: #cccccc;}}
}
</style>
(5)组件使用
<j-mouse-menu:domId="'j-mouse-menu-view-content1'":menu="myMenu"@menuClick="menuClick"
><template v-slot:header><div class="menu-slot-header">🌝JYeontu</div></template><template v-slot:footer><div class="menu-slot">🦁🐼</div></template>
</j-mouse-menu>

通过插槽自定义右键菜单的头部和底部内容,菜单列表通过menu参数传入子组件,并绑定菜单点击事件menuClick

data(){return {myMenu: [{id: "1",label: "菜单1"},{id: "2",label: "菜单2",click: this.test},{id: "3",label: "菜单3"},{id: "4",label: "菜单4"},{id: "5",label: "菜单5"}]}
},
methods:{menuClick(menuItem) {alert("点击了:" + menuItem.label);},test(menuItem) {alert("test-" + menuItem.id);},alert(label) {alert("点击了:" + label);}
}

组件库

组件文档

目前该组件也已经收录到我的组件库,组件文档地址如下:
http://jyeontu.xyz/jvuewheel/#/JMouseMenu

组件内容

组件库中还有许多好玩有趣的组件,如:

  • 悬浮按钮
  • 评论组件
  • 词云
  • 瀑布流照片容器
  • 视频动态封面
  • 3D轮播图
  • web桌宠
  • 贡献度面板
  • 拖拽上传
  • 自动补全输入框
  • 图片滑块验证

等等……

组件库源码

组件库已开源到gitee,有兴趣的也可以到这里看看:https://gitee.com/zheng_yongtao/jyeontu-component-warehouse

觉得有帮助的可以点个star~

有什么问题或错误可以指出,欢迎pr~

有什么想要实现的组件或想法可以联系我~

公众号

关注公众号『前端也能这么有趣』,获取更多有趣内容。

发送『组件库』获取源码

说在后面

🎉 这里是 JYeontu,现在是一名前端工程师,有空会刷刷算法题,平时喜欢打羽毛球 🏸 ,平时也喜欢写些东西,既为自己记录 📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解 🙇,写错的地方望指出,定会认真改进 😊,偶尔也会在自己的公众号『前端也能这么有趣』发一些比较有趣的文章,有兴趣的也可以关注下。在此谢谢大家的支持,我们下文再见 🙌。

http://www.xdnf.cn/news/11437.html

相关文章:

  • asp八大开源cms比较汇总
  • 基于 .NET 6 开发的英雄联盟插件
  • AS3接口详解
  • 主机屋 linux,如何主机屋中发布网站?
  • tbody的解释及用法
  • 【虹科干货】TWAMP:什么是双向主动测量协议?
  • 科技类 企业网站 自适应整站前端html源码,50个页面,值得学习
  • 什么是静态网页
  • Error:kCFStreamErrorCodeKey=-2102 Domain=kCFErrorDomainCFNetwork Code=-1001 - iOS
  • 【CSS】font-weight设置为500显示不出加粗效果
  • WeX5学习笔记
  • 关于斐波拉契数列(Fibonacci)
  • 基数统计算法--HyperLogLog
  • 当 IDENTITY_INSERT 设置为 OFF 时,不能为表中的标识列插入显式值
  • serverlet学习
  • [全程动图]解决Offline Explorer崩溃闪退的问题和一些小技巧(如何下载js、100线程下载)
  • <html> 从0到1的教学实践分享(全网最全)
  • 数据哪里找?200个源数据网站全给你!
  • 如何在路由器上设置PPPoE(ADSL虚拟拨号)上网,即(宽带拨号)?
  • 海量数据处理之Bloom Filter详解
  • MAX10片内User Flash的使用
  • WebWork介绍
  • Kotlin入门学习(非常详细),从零基础入门到精通,看完这一篇就够了
  • jmeter之jtl文件解析(生成测试报告)
  • C语言程序设计(初识C语言后部分)
  • Java中常用术语简称
  • 小米10Pro手机双击android,小米10pro上手感受
  • Data Matrix码
  • DLX算法
  • 操作系统sp1、sp2、sp3是什么意思