必须用 addeventlistener 绑定 contextmenu 事件,不能用 oncontextmenu="return false";现代写法是在回调第一行同步调用 e.preventdefault(),延迟调用会导致原生菜单闪现。

oncontextmenu 事件必须用 addEventListener 绑定,不能靠 return false
直接在 HTML 里写 oncontextmenu="return false" 虽然能禁用菜单,但无法动态控制、不支持事件委托、在 Vue/React 中根本无效。现代标准写法是用 addEventListener('contextmenu', handler),并在回调里同步调用 e.preventDefault()——延迟调用(比如包在 setTimeout 或 Promise.then 里)会导致原生菜单闪现。
常见错误:监听了多次 contextmenu,但只在一个回调里写了 e.preventDefault();或者绑在捕获阶段却没调用它,等冒泡到处理函数时已经晚了。
- 绑定目标推荐
document,再用e.target.matches('.trigger')判断是否命中业务区域 - 若目标是
contenteditable元素或<input>,盲目拦截会破坏粘贴、拼写检查等基础功能 - iframe 内容需单独在其
contentDocument上监听,父页监听无效
自定义菜单 DOM 必须挂载到 body 下,避免定位失效
菜单元素如果插在某个带 transform、overflow: hidden 或 will-change 的父容器里,position: absolute 会受干扰,导致位置偏移甚至被截断。正确做法是把菜单节点直接 appendChild 到 document.body,并设 position: fixed。
坐标要用 e.clientX 和 e.clientY,不是 pageX/pageY(后者含滚动偏移,易错)。但注意:如果页面有缩放或横向滚动,单纯用 client 坐标仍可能错位,稳妥做法是结合 window.scrollX、window.scrollY 校正。
- 菜单渲染后不能立刻读取
getBoundingClientRect()——此时样式未计算,宽高常为 0;应 wrap 在requestAnimationFrame里 - 必须做视口边界检测:若右/下边缘超出,自动改用
right: 0或bottom: 0反向展开 - 不要用
pointer-events: none挡右键——这会连自定义逻辑都触发不了
点击外部关闭菜单时,必须排除菜单自身和触发元素
监听 document.addEventListener('click', ...) 关闭菜单很常见,但点菜单项本身也会触发,导致刚展开就收起。关键是要区分“菜单内点击”和“菜单外点击”。
判断逻辑必须写成:!e.target.closest('.custom-menu') && !e.target.matches('.trigger')。漏掉任一条件都会出问题:不检查 .trigger,右键后点回原元素也会关菜单;不检查 .closest('.custom-menu'),点菜单项就失效。
- ESC 键关闭必不可少:
document.addEventListener('keydown', e => e.key === 'Escape' && hideMenu()) - 滚动时也要隐藏菜单,否则菜单会悬在半空;监听
window.addEventListener('scroll', hideMenu) - 移动端不触发
contextmenu,得用touchstart + setTimeout模拟长按,且要加-webkit-user-select: none减少干扰
无障碍和键盘支持不是可选项,而是硬性要求
仅支持鼠标点击的右键菜单不符合 WCAG 标准。用户用 Shift+F10 或焦点在元素上按 ContextMenu 键打开菜单后,必须支持方向键导航、Enter 触发、Tab 跳出。
<menu></menu> 和 <menuitem></menuitem> 标签已废弃,必须用 ARIA 属性:role="menu"、role="menuitem"、aria-haspopup="true"、aria-expanded="true" 等。菜单关闭后还要显式调用 focus({preventScroll: true}) 恢复原元素焦点,否则焦点丢失。
- 键盘操作必须与鼠标行为完全同步,比如按 ↓ 键聚焦下一个菜单项,同时视觉悬停态也要更新
- 所有菜单项需有
tabindex="0",确保可聚焦 - iOS Safari 对
contextmenu支持极弱,iOS 16+ 才稳定;安卓 Chrome 基本没问题,但系统菜单仍可能叠加弹出
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











