最新要闻
- 【新要闻】一汽奔腾销量惨淡,靠预售23.58万起的奔腾M9有望逆转吗?
- 天天快资讯:车主注意:新一轮国内油价降了!加满一箱油将少花4元
- 焦点要闻:全球最大集装箱船将在宁波舟山港开启首航:比航母还长
- 今日热讯:接二连三胜!长三乙火箭成功发射高分十三号02星
- 环球快资讯:《三体》动画播放量破5亿!豆瓣评分暴跌至3.9 差评率高达86%
- 票房已突破45亿!《满江红》宣布密钥再次延期
- 消防车被小车挡道 业主联系未果合力掀翻!车主不干了
- 滚动:让越野车无路可走!极氪001成功挑战原路虎越野基地
- 世界热门:座椅加热1299元!smart回应硬件订阅:预埋硬件算送的 成本没进卖车价
- 环球快播:何炅再提《快乐大本营》:引发网友感慨
- 当前播报:腊肉的保质期多长?
- 支持小米、OPPO!三星查询手机OLED屏幕网站上线:你用的啥屏?
- 通讯!第二代骁龙7+首次支持双5G双卡双通:4.4Gbps网速、Wi-Fi翻倍
- 观察:性能提升达2倍!真我GT Neo5 SE官宣搭载第二代骁龙7+
- 索尼背水一战!PS5 Pro已在路上
- 环球今热点:刹车失灵?福特全球召回近130万辆汽车
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
每日讯息!记录--vue中封装一个右键菜单组件(复制粘贴即可使用)
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助
组件介绍
关于web端的右键功能常用的地方有表格的右键,或者tab标签的右键等,本文记录一下封装一个右键菜单组件的思路步骤代码。
【资料图】
程序员除了会用轮子,还要尝试去贴合自己公司业务场景造轮子。
组件效果图
我们先看一下右键组件的效果图
组件分析
1.封装组件第一步考虑dom结构
我们观察这个右键菜单,可以明白右键菜单就是一个ul
标签包裹着很多li
标签的弹出层组件,如下图:
每一行都是一个li,每一行中包含图标
和行按钮
名称文字,于是我们的dom结构
可以这样写:
2.dom结构搞清楚了,接下来就是考虑右键菜单组件接收的参数
如何考虑菜单组件接收哪些参数呢?
主要是想组件中会使用到哪些变量。如下:
- 右键菜单需要一个数组,数组中存放的是每个菜单项的数据(菜单项图标、菜单项按钮名字、当然还有一些其他的需要传递的参数,统一挂在一个变量身上,如params)
- 其次右键菜单组件的触发时机是拥挤点击右键的时候,那我们就得知道,用户右键点击的位置x、y的距离,所以这里还需要参数position中的x和y去记录距离视口的clientX和clientY值,因为右键菜单的位置就以这个作基准
- 同时,我们还需要知道用户点击的是哪个菜单项按钮,所以再加一个事件名参数进去
综上所述,我们可以设计右键点击时,要给右键菜单组件传递的参数信息如下:
this.rightclickInfo = { position: { x: event.clientX, y: event.clientY, }, menulists: [ { fnName: "copy", // 事件名字,组件届时可this.$emit(fnName)抛出事件 params: xxx, // 参数,组件届时可this.$emit(fnName,params)抛出事件,并携带参数 icoName: "el-icon-document-copy", // 图标名 btnName: "复制数据", // 菜单项按钮名 // 这三项是发散,可往下看 // divided: true, // 是否禁用 // disabled: true, // 是否带分隔线 // children: [], // 是否有子菜单(递龟) }, { fnName: "look", params: { row, column, event }, icoName: "el-icon-view", btnName: "查看行数据", }, ], };
注意,上述参数代码示例中,多了三个参数divided、disabled、children,实际上,参数的设计要结合业务场景,我司的需求没有右键菜单禁用项,也不用有分割线,以及没有右键菜单的子菜单,所以封装组件就暂时没有加上这三个参数。
组件化、模块化的同时,主要高内聚,一个组件满足业务需求,精简为主,不可无节制的死命封装,否则就变成了
诗山代码
了,当然大家也可以仿照真正右键菜单去加功能,比如右键菜单可以绑定快捷键、改成递归形式等更多功能...
所以组件props中接收参数可以写成:
props: { // 接收右键点击的信息 rightclickInfo: { type: Object, default: () => { return { position: { // 右键点击的位置 x: null, y: null, }, menulists: [ { fnName: "", // 点击菜单项的事件名 params: {}, // 点击的参数 icoName: "", // 图标名 btnName: "", // 按钮名 }, ], }; }, }, },
3.实现右键打开菜单弹出层,左键点击一下菜单弹出层就关闭了
不难发现,只要一右键菜单就弹出,点一下菜单消失,这种不停的显示和消失,去不停的v-if
就不合适了,所以这里可以从v-show
的角度出发
- 一开始让菜单层隐藏
display:none
,而后再设置成dispaly:block
- 当右键点击时,右键点击的位置参数
position
的x和y
的值就会发生变化 - 我们可以
watch
监听这个变化,position的x、y
值变了,说明右键点击了 - 右键点击了,我们就可以让菜单弹出层出现
- 同时,需要监听鼠标点击事件,当点击的是右键或者中间滚轮键时,不去隐藏面板,点击的是左键时,才去隐藏面板
通过上述五点,我们即做到了显示隐藏菜单面板了
4.监听右键位置变化,显示菜单项代码
这一块的思路请看代码中注释即可,如下:
.table-right-menu { dispaly:none; // 初始为隐藏,监听更改显示}watch: { // 监听右键点击时点击位置的变化,只要变化了,就弹出右键菜单供用户点击操作 "rightclickInfo.position"(val) { let x = val.x; // 获取x轴坐标 let y = val.y; // 获取y轴坐标 let innerWidth = window.innerWidth; // 获取页面可是区域宽度,即页面的宽度 let innerHeight = window.innerHeight; // 获取可视区域高度,即页面的高度 /** * 注意,这里要使用getElementsByClassName去选中对应dom,因为右键菜单组件可能被多处使用 * classIndex标识就是去找到对应的那个右键菜单组件的,需要加的 * */ let menu = document.getElementsByClassName("table-right-menu")[this.classIndex]; menu.style.display = "block"; // 由隐藏改为显示 let menuHeight = this.rightclickInfo.menulists.length * 30; // 菜单容器高 let menuWidth = 180; // 菜单容器宽 // 菜单的位置计算(边界留点间隙空间) menu.style.top = (y + menuHeight > innerHeight ? innerHeight - menuHeight : y) + "px"; menu.style.left = (x + menuWidth > innerWidth ? innerWidth - menuWidth : x) + "px"; // 因为菜单还要关闭,就绑定一个鼠标点击事件,通过e.button判断点击的是否是左键,左键关闭菜单 document.addEventListener("mouseup", this.hide, false); }, }, hide(e) { if (e.button === 0) { // 0是左键、1是滚轮按钮或中间按钮(若有)、2鼠标右键 let menu = document.querySelector(".table-right-menu"); menu.style.display = "none"; // 菜单关闭 document.removeEventListener("mouseup", this.hide); // 及时解绑监听事件 }},
事件绑定后别忘了解绑 document.removeEventListener("mouseup", this.hide);
5.知识点回顾e.button
e.button
,鼠标事件- 返回一个数字,表示触发鼠标事件的是按下了哪个按钮
- 值为只读,不可修改
具体返回数字值,表示鼠标事件发生时按下的鼠标按钮。
可能的值:
0:鼠标左键、 1:滚轮按钮或中间按钮(如果有)、 2:鼠标右键
IE8返回有一些不同:1:鼠标左键、 2:鼠标右键、 4:滚轮按钮或中间按钮(如果有)
注意:左手鼠标,返回值相反
6.组件中的事件要抛出去哦
item即为循环的菜单项,包含事件名、参数、图标名、按钮名
fnHandler(item) { this.$emit(item.fnName, item.params); // 事件再传出去,即为: // this.$emit("事件名",事件参数)},
7.外界接收事件,正常@xxx="xxx"使用即可
如下:
使用组件
搭配el-table使用
el-table中可以使用封装好的事件:
@row-contextmenu="xxx"
然后在xxx方法中去传递参数给右键菜单组件即可,如下简化代码:
... rightclickInfo:{}// 饿了么UI封装好的右键菜单事件,可直接使用,有行数据,列数据,以及事件rightclick(row, column, event) { this.rightclickInfo = { position: { x: event.clientX, y: event.clientY, }, menulists: [ { fnName: "copy", params: { row, column, event }, icoName: "el-icon-document-copy", btnName: "复制数据", }, ], }; event.preventDefault(); // 阻止默认的鼠标右击事件},
event.preventDefault()
要加上,阻止默认的右键菜单事件
搭配普通dom使用
也同理,传参的时,需要阻止默认时间,如下:
区域内右键onContextmen(){ // 定义参数传递给my-right-menu组件}
完整代码
复制粘贴即可使用哦
使用组件代码
<script>export default { name: "myRightMenuName", data() { return { tableData: [ { id: "1", name: "孙悟空", age: 500, home: "花果山水帘洞", hobby: "桃子", }, { id: "2", name: "猪八戒", age: 88, home: "高老庄", hobby: "肉包子", }, { id: "3", name: "沙和尚", age: 500, home: "通天河", hobby: "游泳", }, { id: "4", name: "唐僧", age: 1000, home: "东土大唐", hobby: "吃斋念经", }, ], rightclickInfo: {}, }; }, methods: { // 饿了么UI封装好的右键菜单事件,可直接使用 rightclick(row, column, event) { this.rightclickInfo = { position: { x: event.clientX, y: event.clientY, }, menulists: [ { fnName: "copy", params: { row, column, event }, icoName: "el-icon-document-copy", btnName: "复制数据", // divided: true, // disabled: true, // children: [], }, { fnName: "look", params: { row, column, event }, icoName: "el-icon-view", btnName: "查看行数据", }, { fnName: "edit", params: { row, column, event }, icoName: "el-icon-edit", btnName: "编辑行数据", }, { fnName: "delete", params: { row, column, event }, icoName: "el-icon-delete", btnName: "删除行数据", }, { fnName: "refresh", params: { row, column, event }, icoName: "el-icon-refresh", btnName: "刷新页面", }, ], }; event.preventDefault(); // 阻止默认的鼠标右击事件 }, copy(params) { console.log( "copy", params.row ? params.row[params.column.property] : params ); }, look(params) { console.log("look", params.row ? JSON.stringify(params.row) : params); }, edit(params) { console.log("edit", params); }, deleteFn(params) { console.log("deleteFn", params.row ? params.row.id : params); }, refresh(params) { console.log("refresh 刷新页面啦"); }, // 普通dom右键 onContextmenu(e) { this.rightclickInfo = { position: { x: e.clientX, y: e.clientY, }, menulists: [ { fnName: "copy", params: "代码修仙", icoName: "el-icon-star-on", btnName: "代码修仙", }, { fnName: "look", params: "路漫漫", icoName: "el-icon-star-off", btnName: "路漫漫", }, ], }; }, },};</script>表格内右键
区域内右键
封装组件代码
<script>export default { name: "myRightMenu", props: { // 接收右键点击的信息 rightclickInfo: { type: Object, default: () => { return { position: { // 右键点击的位置 x: null, y: null, }, menulists: [ { fnName: "", // 点击菜单项的事件名 params: {}, // 点击的参数 icoName: "", // 图标名 btnName: "", // 按钮名 }, ], }; }, }, // 重要参数,用于标识是哪个右键菜单dom元素 classIndex: { type: Number, default: 0, }, }, watch: { // 监听右键点击时点击位置的变化,只要变化了,就弹出右键菜单供用户点击操作 "rightclickInfo.position"(val) { let x = val.x; // 获取x轴坐标 let y = val.y; // 获取y轴坐标 let innerWidth = window.innerWidth; // 获取页面可是区域宽度,即页面的宽度 let innerHeight = window.innerHeight; // 获取可视区域高度,即页面的高度 /** * 注意,这里要使用getElementsByClassName去选中对应dom,因为右键菜单组件可能被多处使用 * classIndex标识就是去找到对应的那个右键菜单组件的,需要加的 * */ let menu = document.getElementsByClassName("table-right-menu")[this.classIndex]; menu.style.display = "block"; let menuHeight = this.rightclickInfo.menulists.length * 30; // 菜单容器高 let menuWidth = 180; // 菜单容器宽 // 菜单的位置计算 menu.style.top = (y + menuHeight > innerHeight ? innerHeight - menuHeight : y) + "px"; menu.style.left = (x + menuWidth > innerWidth ? innerWidth - menuWidth : x) + "px"; // 因为菜单还要关闭,就绑定一个鼠标点击事件,通过e.button判断点击的是否是左键,左键关闭菜单 document.addEventListener("mouseup", this.hide, false); }, }, methods: { hide(e) { if (e.button === 0) { // 0是左键、1是滚轮按钮或中间按钮(若有)、2鼠标右键 let menu = document.getElementsByClassName("table-right-menu")[this.classIndex]; // 同样的精确查找 menu.style.display = "none"; // 菜单关闭 document.removeEventListener("mouseup", this.hide); // 及时解绑监听事件 } }, fnHandler(item) { this.$emit(item.fnName, item.params); // 事件再传出去,即为: // this.$emit("事件名",事件参数) }, },};</script>
本文转载于:
https://juejin.cn/post/7174420692954251272
如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。
关键词:
全球新消息丨如何在Docker下部署nacos并注册Java服务
每日讯息!记录--vue中封装一个右键菜单组件(复制粘贴即可使用)
【新要闻】一汽奔腾销量惨淡,靠预售23.58万起的奔腾M9有望逆转吗?
天天快资讯:车主注意:新一轮国内油价降了!加满一箱油将少花4元
焦点要闻:全球最大集装箱船将在宁波舟山港开启首航:比航母还长
今日热讯:接二连三胜!长三乙火箭成功发射高分十三号02星
环球快资讯:《三体》动画播放量破5亿!豆瓣评分暴跌至3.9 差评率高达86%
票房已突破45亿!《满江红》宣布密钥再次延期
全球热门:“315”曝光:带货直播间水军泛滥,该如何应对?
天天观速讯丨债市日报:3月17日
消防车被小车挡道 业主联系未果合力掀翻!车主不干了
滚动:让越野车无路可走!极氪001成功挑战原路虎越野基地
世界热门:座椅加热1299元!smart回应硬件订阅:预埋硬件算送的 成本没进卖车价
环球快播:何炅再提《快乐大本营》:引发网友感慨
全球实时:1个案例读懂——游戏产品如何用 A/B 测试做增长
当前消息!Tailwind CSS 备忘清单_开发速查表分享
python __new__方法与单例模式
【当前热闻】前端有边界,但低代码没有
【快播报】Application Loader及Transporter App上传ipa外、可以在Windows上架iOS APP工具
当前播报:腊肉的保质期多长?
法兴银行:欧洲央行加息对欧元区国家息差的影响越来越小
支持小米、OPPO!三星查询手机OLED屏幕网站上线:你用的啥屏?
通讯!第二代骁龙7+首次支持双5G双卡双通:4.4Gbps网速、Wi-Fi翻倍
观察:性能提升达2倍!真我GT Neo5 SE官宣搭载第二代骁龙7+
索尼背水一战!PS5 Pro已在路上
环球今热点:刹车失灵?福特全球召回近130万辆汽车
世界热资讯!使用代理以及搭建代理池
河南突降大雪:农户40亩葡萄棚被压塌、郑州多个仓库倒塌损失惨重
天天快看点丨卢伟冰现身高通发布会!Redmi全球首发第二代骁龙7+
动态焦点:性能提升2倍!高通正式发布第二代骁龙7+移动平台
环球快消息!前端使用EasyWasmPlayer.js接入hls协议h265编码视频
当前速讯:[EF Core] EF Core Code-First 移除外键 —— 重写SQL生成器
当前快看:带发行版 Logo 的系统信息显示工具
天天快报!歌曲.在我心里没有谁能够代替你原唱_在我心里没有谁能代替你简谱歌谱
文心一言申请测试企业达7.6万 百度股价上涨近15%
锦心似玉林世显是什么身份?锦心似玉林世显的出场有什么作用吗?
人世间冯化成哪集出轨的?人世间冯化成最后的结局是什么?
小米3的充电线是哪种头?小米3手机跑分是多少?
小天鹅洗衣机脱水不干是什么原因?小天鹅洗衣机24小时服务热线
热议:zynq基于DMA的串口传图
天龙八部单机版怎么下载?天龙八部单机版武功搭配
环球头条:899元 雷蛇帝王蝶鼠标垫发布:钢化玻璃一体成型
天天微速讯:6岁女童看店 2人用98元买走60根虫草引热议:无耻不道德行为、交易无效
全球简讯:特斯拉不好惹!网红车评人“蔡老板”被判道歉赔10万后:维持原判 不得上诉
落地成盒!苹果可折叠手机新专利:掉落自动闭合
环球观察:又一网红店翻车 半天妖烤鱼被曝垃圾桶捞回餐食又端上桌 你吃过没
今头条!python 排序算法
天天通讯!uni-app 实现轮播图组件父容器背景色随图片主题色改变
全球短讯!iQOO Z7对标旗舰配置:OIS光学防抖、NFC全都有
性价比领先RTX 3060多达78% Intel Arc新驱动优化《暗黑4》等游戏
造谣蔚来因质量失控酿车祸 车评人被判向蔚来道歉、赔偿8万元
全球快报:发放37亿元购车补贴 单车最高降价5万!上汽大众回应
焦点速读:58元 国产单机游戏《二分之一》正式发售:近百位角色 文本超25万字
【时快讯】好多人说驱鼠器不管用是真的吗为什么(好多人说驱鼠器不管用是真的吗)
热点在线丨前端操作cookie的用法
世界最新:数据湖选型指南|Hudi vs Iceberg 数据更新能力深度对比
快讯:全网最详细中英文ChatGPT接口文档(四)30分钟快速入门ChatGPT——Models模型
git回退到某个提交
世界微头条丨交易商协会对中航租赁予以通报批评
女子地铁上辱骂殴打男子 通报来了:拘留10天 罚款500
动物园母猴产后啃食夭折小猴 工作人员:有一定野性、比较常见
环球讯息:零百加速1.9秒 中国第一超跑埃安Hyper SSR量产已达50%
消息!别喝工业水啤了:熊猫精酿杀马特扯皮小麦啤酒6听19.9元大促
全球微速讯:20.98万起大杀四方 新款比亚迪唐DM-i、汉EV上市当日狂卖8196台
【全球聚看点】Java 枚举实现单例模式,线程安全又优雅!
天天讯息:前端设计模式——组合模式
全球快播:[issues] webrtc 接入SRS丢包率不正确问题
天天热资讯!你居然还不会判定表法?
资讯:【微电平台】-高并发实战经验-奇葩问题解决之旅
快递员骑摩托与特斯拉相撞当场身亡 现场惨烈:司机喊话车没失控
焦点短讯!大众最便宜电车来了!截胡特斯拉Model Q
天天要闻:生财有道?特斯拉圆形方向盘开卖:售价4800元
德系不装了!上汽大众全系车型开降:最多补贴5万元
当前热讯:超5000米 世界最高海拔风电场发电量超1亿度 中国再创纪录
【天天聚看点】济南遥墙国际机场二期改扩建工程项目房屋征收范围确定
每日时讯!Linux进程通信 | 消息队列
天天时讯:银行援助方案缓解市场担忧 美债收益率普遍回升
天天最资讯丨苏南硕放机场更名无锡苏州机场?官方回应:没改名
世界观焦点:大学生组团到工地吃13元盒饭 20种菜任选味道棒:老板回应物美价廉不怕竞争
迄今最好的长焦旗舰!OPPO Find X6系列来了
摊上事:联想被判向美国公司赔偿近10亿授权费 侵犯5G专利等
【天天新要闻】我国率先研发 全球6G技术大会即将召开:2030年商用
读Java性能权威指南(第2版)笔记19_垃圾回收F
【全球独家】聊聊缓存
环球动态:自动驾驶驶向何方
天天动态:高通胀正掏空美国人储蓄 近半民众陷入财务困境:鸡蛋都吃不起节奏
为了改桥接,我决定破解中兴F450G V2光猫
每日快报!贵州贵阳多地突降冰雹!现场视频画面:还伴随闪电
国内成品油零售价今晚即将下调:预计下跌0.05元/升!
世界新动态:体验完百度的文心一言 我只能说:它胆子够大!
天天热点评!好评率98%的民国武侠动作游戏:终于要上手游了!
天天观焦点:生产力起飞!微软正式推出Microsoft 365 Copilot:AI全面植入Office全家桶
据报道 特斯拉Model S的纽伯格林赛道比保时捷Taycan还快
NodeJS 实战系列:模块设计与文件分类
环球新动态:计算,存储,网络虚拟化区别
当前热门:加速颠覆燃油车!汉、唐冠军版上市:双车20.98万起
全球快看:从小吃到大的腌菜 竟是“垃圾堆”生产?被315暴击的进来
即时看!MyBatis
当前快看:群友们的表情包《九十期》
每日视点!男子镜头前嗨舞被羊顶翻 网友看完大笑:做人不能太狂浪