当用户右键单击页面时,浏览器将显示默认上下文菜单。有时,我们希望用自己的菜单替换默认菜单,允许用户执行其他操作。
这篇文章演示了一个简单的实现。首先,让我们创建一个元素,以显示自定义的上下文菜单元素:
<div id="element">Right-click me</div>
<ul id="menu">...</menu>
为了做到这一点,我们只需阻止 contextmenu
事件的默认操作:
const ele = document.getElementById('element')
ele.addEventListener('contextmenu', (e) => {
e.preventDefault()
})
我们将计算菜单的位置,但首先需要绝对定位到其容器。因此,让我们将元素和菜单放置到位置 relative
的容器中:
<div class="relative">
<div id="element">Right-click me</div>
<ul id="menu" class="absolute hidden">...</menu>
</div>
relative
、absolute
和 hidden
类定义如下:
.relative {
position: relative;
}
.absolute {
position: absolute;
}
.hidden {
/* 菜单一开始是隐藏的 */
display: none;
}
现在是设置菜单位置的时候了。可根据鼠标位置计算:
ele.addEventListener('contextmenu', (e) => {
const rect = ele.getBoundingClientRect()
const x = e.clientX - rect.left
const y = e.clientY - rect.top
// 设置菜单的位置
menu.style.top = `${y}px`
menu.style.left = `${x}px`
// 显示菜单
menu.classList.remove('hidden')
})
我们可以处理 document
的 click
事件,并确定用户是否在菜单外单击:
ele.addEventListener('contextmenu', (e) => {
// ...
document.addEventListener('click', documentClickHandler)
})
// 在菜单外部单击时隐藏菜单
const documentClickHandler = (e) => {
const isClickedOutside = !menu.contains(e.target)
if (isClickedOutside) {
// 隐藏菜单
menu.classList.add('hidden')
// 移除事件处理程序
document.removeEventListener('click', documentClickHandler)
}
}
通过添加 hidden
类可以隐藏菜单。
更重要的是,click
事件处理程序也从 document
中删除,因为当菜单隐藏时,我们不需要处理它。