JS实现页面右键菜单
前言
右键菜单也算是前端页面中比较常见的功能了,今天我就带大家完整的实现右键菜单功能。
contextmenu事件
实现右键菜单我们需要用到 oncontextmenu
事件,oncontextmenu
事件会在用户右击鼠标时触发。
阻止原有菜单
首先,我们将其绑定到window
上:window.oncontextmenu
。
然后,通过event.preventDefault()
方法阻止掉原有的右键菜单,为我们绑定上新的功能做好准备工作。
window.oncontextmenu = function(e){//取消默认的浏览器自带右键e.preventDefault();}
创建菜单
创建对应菜单的dom结构,并绑定上对应的功能函数:
<div id="menu" class="menu"><div class="menu__item" onclick="log('1')">功能1</div><div class="menu__item" onclick="log('2')">功能2</div><div class="menu__item" onclick="log('3')">功能3</div><div class="menu__item">功能4 <span class="icon"> > </span><div id="submenu" class="submenu"><div class="submenu__item" onclick="log('4-1')">功能4-1</div><div class="submenu__item" onclick="log('4-2')">功能4-2</div><div class="submenu__item" onclick="log('4-3')">功能4-3</div><div class="submenu__item" onclick="log('4-4')">功能4-4</div></div></div><div class="menu__item" onclick="log(5)">功能5</div></div>
当然,现在它还是固定的,不能移动。
菜单随鼠标联动
我们将菜单绝对定位,然后利用event的clientX/clientY
属性,将获取的触发点坐标动态赋给菜单的top/left
属性,这样菜单就可以跟鼠标联动了。
const menu=document.getElementById('menu');//根据事件对象中鼠标点击的位置,进行定位menu.style.left=e.clientX+'px';menu.style.top=e.clientY+'px';
现在菜单虽然能跟鼠标联动了,但它现在还不能在默认情况下隐藏。
怎么办?
菜单显隐
很简单,我们先将菜单通过visibility: hidden;
隐藏;
.menu{position: absolute;top:0px;left: 0px;background: #fff;border: 1px solid #dadce0;visibility: hidden;}.active{visibility: visible;}
然后再触发 window.oncontextmenu
的时候,添加active
显示菜单;
menu.classList.add('active');
现在,菜单功能基本完成了,只需要在 window
上绑定点击事件,然后将active
移出,即可隐藏掉菜单;
//关闭右键菜单window.addEventListener('click', function() {menu.classList.remove('active');})
到此右键菜单功能的基本功能我们就实现了,但它存在溢出的问题。
菜单溢出
菜单溢出就是在页面的边缘触发右键菜单时,由于触发点距离页面边缘距离小于右键菜单的宽度,所产生菜单显示不全的问题。
子菜单溢出
子菜单溢出也是一样的,就是菜单距离页面边缘的距离小于子菜单的宽度时,出现的子菜单显示不全问题。
解决溢出
要解决溢出问题,我们就得先计算一下,menu.style.left
最大值;
由图可知:
当e.offsetX == window.innerWidth - menu.offsetWidth
时,菜单刚好不会溢出,
当e.offsetX > window.innerWidth - menu.offsetWidth
时,菜单就会溢出;
所以,menu.style.left
最大值是window.innerWidth - menu.offsetWidth
。
即,当e.offsetX >= window.innerWidth - menu.offsetWidth
时,menu.style.left = window.innerWidth - menu.offsetWidth
;
当 e.offsetX < window.innerWidth - menu.offsetWidth
时,menu.style.left = e.offsetX
。
const menu=document.getElementById('menu');let x = e.offsetX; //触发点到页面窗口左边的距离let winWidth = window.innerWidth; //窗口的内部宽度(包括滚动条)let menuWidth = menu.offsetWidth; //菜单宽度,高度包含内边距(padding)和边框(border),不包含外边距(margin)x = winWidth - menuWidth >= x ? x : winWidth -menuWidth;menu.style.left = x +'px';
解决子菜单溢出
解决子菜单溢出也是同理,在此基础上再减去子菜单的宽度即可。
const submenu=document.getElementById('submenu');if(x > (winWidth -menuWidth - submenu.offsetWidth)){submenu.style.left = '-200px';}else{submenu.style.left ='';submenu.style.right ='-200px';}
最后效果
示例代码
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>.menu{position: absolute;top:0px;left: 0px;background: #fff;border: 1px solid #dadce0;visibility: hidden;}.active{visibility: visible;}.menu__item, .submenu__item{width: 200px;height: 20px;}.menu__item:hover, .submenu__item:hover{background-color: #dadce0;}.menu__item:hover .submenu{opacity: 1;}.submenu{position: relative;top:-20px;left: 200px;opacity: 0;background: #fff;border: 1px solid #dadce0;}.icon{position: absolute;right: 3px;}</style>
</head>
<body><div id="menu" class="menu"><div class="menu__item" onclick="log('1')">功能1</div><div class="menu__item" onclick="log('2')">功能2</div><div class="menu__item" onclick="log('3')">功能3</div><div class="menu__item">功能4 <span class="icon"> > </span><div id="submenu" class="submenu"><div class="submenu__item" onclick="log('4-1')">功能4-1</div><div class="submenu__item" onclick="log('4-2')">功能4-2</div><div class="submenu__item" onclick="log('4-3')">功能4-3</div><div class="submenu__item" onclick="log('4-4')">功能4-4</div></div></div><div class="menu__item" onclick="log(5)">功能5</div></div><script>window.onload = function() {const menu=document.getElementById('menu');const submenu=document.getElementById('submenu');window.oncontextmenu=function(e){//取消默认的浏览器自带右键e.preventDefault();let x = e.offsetX; //触发点到页面窗口左边的距离let y = e.offsetY;let winWidth = window.innerWidth; //窗口的内部宽度(包括滚动条)let winHeight = window.innerHeight;let menuWidth = menu.offsetWidth; //菜单宽度let menuHeight = menu.offsetHeight;x = winWidth - menuWidth >= x ? x : winWidth -menuWidth;y = winHeight - menuHeight >= y ? y : winHeight - menuHeight;menu.style.top = y+'px';menu.style.left = x +'px';if(x > (winWidth -menuWidth - submenu.offsetWidth)){submenu.style.left = '-200px';}else{submenu.style.left ='';submenu.style.right ='-200px';}menu.classList.add('active');}// 关闭右键菜单window.addEventListener('click', function() {menu.classList.remove('active');})}// 菜单功能测试function log(i){alert(i);}</script>
</body>
</html>
到此完整的右键菜单功能我们就实现了
如果大家还有什么其他想法,欢迎在评论区交流!
JS实现页面右键菜单相关推荐
- 禁止页面复制功能 js禁止复制 禁用页面右键菜单
<body οncοntextmenu="return false">禁用网页右键菜单,但是仍然可以使用快捷键复制. js代码禁用复制功能: <script t ...
- Chrome 插件开发-右键菜单开发实战演示,浏览器页面右键菜单选项设置,插件右键菜单点击插件名跳转主页设置
Chrome 插件开发 - 菜单选项 浏览器页面右键菜单选项设置 ① 核心代码演示 ② 效果展示 ③ 详细参数文档 插件右键菜单点击插件名跳转主页设置 ① 核心代码演示 ② 演示效果图 浏览器页面右键 ...
- 关于FlexPaper 2.1.2版本 二次开发 Logo 、打印、搜索、缩略图、添加按钮、js交互、右键菜单等相关问题...
原文:关于FlexPaper 2.1.2版本 二次开发 Logo .打印.搜索.缩略图.添加按钮.js交互.右键菜单等相关问题 先废话几句.最近用到文档在线浏览功能,之前用的是print2flash( ...
- 页面右键菜单Beta2(兼容fw)
//右键菜单js代码开始 var newX,newY; document.onmousedown = function popUp(obj) { if(document.all)//判断IE.Fire ...
- 青铜修炼手册:Axure页面右键菜单制作
右键菜单这个功能我觉得大家都应该不陌生吧,这个功能应该成为我们浏览网页的必备技能了,但是我们有时候发现点击不同的东西出来的右键菜单都是不一样的,就如下图一样,在矩形内点击右键和在页面内点击右键出来的菜 ...
- go.js 节点添加右键菜单
公司项目开发时,采用了go.js绘制节点关系图,需添加右键功能,采坑经历分享. go.js API文档不太好懂,开发功能时,建议从实例入手,然后再去看API文档查找相关属性用法 就很容易理解了.如图: ...
- js 解除网页右键菜单被禁用
问题: 有些时候 需要复制页面的一些东西或者检查源码 但页面右键被被作者禁用了,碰到过几次,就记录下来希望对大家有多帮助. 解决方法: 在浏览器「控制台」执行一下代码即可. PS:无法打开控制台,请移 ...
- 一个不错的js制作的右键菜单
网上转的,比我自己写的方便拓展,所以转过来~<html> <head> <script language='javascript'> /*******以下内容可以修 ...
- UnityWebPlayer使用(3) WinForm中屏蔽右键菜单
百度到的解决方案: 鼠标右键的BUG 1).3D模型基本操作都是鼠标右键按下以后,拖动鼠标可以旋转模型视角,但是WPF加载后的UnityWebPlayer控件存在一个BUG:右键菜单 ...
最新文章
- 004_常用词汇句子翻译记录
- AI 时代保护儿童刻不容缓!智源研究院发布我国首个儿童人工智能发展原则《面向儿童的人工智能北京共识》...
- BZOJ1061 [NOI2008]志愿者招募
- 提高你开发效率的十五个Visual Studio 2010使用技巧
- linux下查看目录下某种文件类型累计的代码行数
- sublime插件调用第三方程序
- JPA开发求助---JPA生成数据表的时候:log4j:WARN No appenders could be found for logger (org.hibernate.cfg.annotat
- “乐享生活,随心而行”,第四届APEC车联网研讨会即将在上海召开
- linux 运行python效率高还是windows高_为什么使用Mac开发比Windows效率高?
- 浅谈C#实现Web代理服务器的几大步骤
- 后端返回文件,前端下载导出
- 详解云安全攻防模型,这些攻击战略和战术越早知道越好!
- 深度探索C++对象模型
- 51单片机学习笔记——STC15W201S系列
- Vue的渐进式怎么理解
- 数据结构 - 主席树
- 《信息物理融合系统(CPS)设计、建模与仿真——基于 Ptolemy II 平台》——第2章 图形化建模 2.1开始...
- 在开发环境使用 TiUP安装TiDB集群
- 百度云虚拟服务器win,百度云- 使用xshell连接windows服务器
- 《你一学就会的-思维大图》读书笔记