前言

右键菜单也算是前端页面中比较常见的功能了,今天我就带大家完整的实现右键菜单功能。

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实现页面右键菜单相关推荐

  1. 禁止页面复制功能 js禁止复制 禁用页面右键菜单

    <body οncοntextmenu="return false">禁用网页右键菜单,但是仍然可以使用快捷键复制. js代码禁用复制功能: <script  t ...

  2. Chrome 插件开发-右键菜单开发实战演示,浏览器页面右键菜单选项设置,插件右键菜单点击插件名跳转主页设置

    Chrome 插件开发 - 菜单选项 浏览器页面右键菜单选项设置 ① 核心代码演示 ② 效果展示 ③ 详细参数文档 插件右键菜单点击插件名跳转主页设置 ① 核心代码演示 ② 演示效果图 浏览器页面右键 ...

  3. 关于FlexPaper 2.1.2版本 二次开发 Logo 、打印、搜索、缩略图、添加按钮、js交互、右键菜单等相关问题...

    原文:关于FlexPaper 2.1.2版本 二次开发 Logo .打印.搜索.缩略图.添加按钮.js交互.右键菜单等相关问题 先废话几句.最近用到文档在线浏览功能,之前用的是print2flash( ...

  4. 页面右键菜单Beta2(兼容fw)

    //右键菜单js代码开始 var newX,newY; document.onmousedown = function popUp(obj) { if(document.all)//判断IE.Fire ...

  5. 青铜修炼手册:Axure页面右键菜单制作

    右键菜单这个功能我觉得大家都应该不陌生吧,这个功能应该成为我们浏览网页的必备技能了,但是我们有时候发现点击不同的东西出来的右键菜单都是不一样的,就如下图一样,在矩形内点击右键和在页面内点击右键出来的菜 ...

  6. go.js 节点添加右键菜单

    公司项目开发时,采用了go.js绘制节点关系图,需添加右键功能,采坑经历分享. go.js API文档不太好懂,开发功能时,建议从实例入手,然后再去看API文档查找相关属性用法 就很容易理解了.如图: ...

  7. js 解除网页右键菜单被禁用

    问题: 有些时候 需要复制页面的一些东西或者检查源码 但页面右键被被作者禁用了,碰到过几次,就记录下来希望对大家有多帮助. 解决方法: 在浏览器「控制台」执行一下代码即可. PS:无法打开控制台,请移 ...

  8. 一个不错的js制作的右键菜单

    网上转的,比我自己写的方便拓展,所以转过来~<html> <head> <script language='javascript'> /*******以下内容可以修 ...

  9. UnityWebPlayer使用(3) WinForm中屏蔽右键菜单

    百度到的解决方案:     鼠标右键的BUG      1).3D模型基本操作都是鼠标右键按下以后,拖动鼠标可以旋转模型视角,但是WPF加载后的UnityWebPlayer控件存在一个BUG:右键菜单 ...

最新文章

  1. 004_常用词汇句子翻译记录
  2. AI 时代保护儿童刻不容缓!智源研究院发布我国首个儿童人工智能发展原则《面向儿童的人工智能北京共识》...
  3. BZOJ1061 [NOI2008]志愿者招募
  4. 提高你开发效率的十五个Visual Studio 2010使用技巧
  5. linux下查看目录下某种文件类型累计的代码行数
  6. sublime插件调用第三方程序
  7. JPA开发求助---JPA生成数据表的时候:log4j:WARN No appenders could be found for logger (org.hibernate.cfg.annotat
  8. “乐享生活,随心而行”,第四届APEC车联网研讨会即将在上海召开
  9. linux 运行python效率高还是windows高_为什么使用Mac开发比Windows效率高?
  10. 浅谈C#实现Web代理服务器的几大步骤
  11. 后端返回文件,前端下载导出
  12. 详解云安全攻防模型,这些攻击战略和战术越早知道越好!
  13. 深度探索C++对象模型
  14. 51单片机学习笔记——STC15W201S系列
  15. Vue的渐进式怎么理解
  16. 数据结构 - 主席树
  17. 《信息物理融合系统(CPS)设计、建模与仿真——基于 Ptolemy II 平台》——第2章 图形化建模 2.1开始...
  18. 在开发环境使用 TiUP安装TiDB集群
  19. 百度云虚拟服务器win,百度云- 使用xshell连接windows服务器
  20. 《你一学就会的-思维大图》读书笔记

热门文章

  1. Docker Daemon
  2. AR9344开发环境的搭建和编译固件
  3. AR9341刷机资料
  4. 【备忘】最新spark/hadoop/hbase/hive/kafka/redies大数据视频教程
  5. 置信区间(已知样本均值和样本的方差,求总体均值的置信区间)(n 30)
  6. 三星苹果盛极而衰,国产手机迎来分化
  7. 去培训基础报班学UI设计靠谱吗?
  8. linode上搭建有standby+mirror功能的Greenplum集群并用TPC-DS基准测试
  9. 拆解康柏321电池之电池串并联容量计算
  10. Transparent和Fade的区别