如何在需要检测鼠标悬停的元素下方仍然允许指针事件?(dHTML)
概览
在HTML、CSS和 JS里,我做了一个可以通过点击隐藏的侧边栏。我也尝试让用户将鼠标悬停在侧边栏原本的位置上,以显示一个按钮,之后再通过按钮把它重新显示出来。
我尝试过的做法
起初我尝试pointer-events: none,让点击穿透隐藏的侧边栏,但那样就无法检测鼠标在侧边栏上的悬停。
我做了一个矩形div(尺寸与侧边栏相同),但它是透明的并且 position: absolute,以不影响其他元素。它会等待 "mouseover" 事件来显示按钮,接着在 "mouseenter" 事件时将按钮移动到光标的纵向坐标处(以便用户更容易点击)。随后它再等待 "mouseleave" 来隐藏。但这个修复并不能让点击穿透到侧边栏。
问题
如何修复这段代码,使用户能够在侧边栏下方按下按钮,同时又能将鼠标悬停在侧边栏元素上?
示例
(这段代码并非我正在处理的代码,但作为示例包含了这个普遍的问题):
// the hidden sidebar detecting mouse movements
let hiddenSidebarDiv = document.querySelector("[data-js-tag='hidden-sidebar']");
// the button that should bring back the sidebar when pressed
let showSidebarButton = hiddenSidebarDiv.querySelector("[data-js-tag='show-sidebar-button']");
showSidebarButton.classList.add("hide");
let moveButton = (mousePosition = {x: 0, y: 0}) => {
showSidebarButton.style.top = `${mousePosition.y}px`;
}
hiddenSidebarDiv.addEventListener("mouseover", (event) => {
showSidebarButton.classList.remove("hide");
});
hiddenSidebarDiv.addEventListener("mouseenter", (event) => {
moveButton({x: event.x, y: event.y});
});
hiddenSidebarDiv.addEventListener("mouseleave", (event) => {
showSidebarButton.classList.add("hide");
});
hiddenSidebarDiv.addEventListener("click", (event) => {
showSidebarButton.classList.add("hide");
});
body{
padding: 25px;
background-color: #32442e;
padding: 0;
}
.title {
color: #a2a323;
}
button {
color: #a2a323;
background-color: #12141e;
}
.hidden-sidebar{
position: fixed;
background-color: #03030313; /*not fully transparent only to clearly show the problem*/
/*background-color: transparent; is what I want*/
width: 100px;
height: 100vh;
left: 0;
top: 0;
}
.hide{
display: none;
}
.show-sidebar-button{
position: fixed;
}
<!DOCTYPE html>
<html>
<head>
<title>Hello, World!</title>
<link rel="stylesheet" href="styles.css" />
<script src="script.js" type="text/javascript" charset="utf-8" defer></script>
</head>
<body>
<h1 class="title">Some content</h1>
<button data-js-tag="detect-button-press">a button that should be pressable even with the hidden sidebar above it</button>
<div data-js-tag="hidden-sidebar" class="hidden-sidebar">
<button data-js-tag="show-sidebar-button" type="submit" class="hide show-sidebar-button">bring sidebar back</button>
</div>
</body>
</html>
解决方案
你的代码存在一个严重的问题。你想要实现的逻辑本身没有问题,但把它写成代码时,你在某个细节上(很微妙的地方,或许并不那么微妙)犯了一个错误,导致功能被破坏。
你的思路是通过检测鼠标是否悬停在一个透明的 div 上来显示一个名为 “side_bar” 的元素;如果是,那么一个按钮就会出现来显示它……问题在于,在你的代码里,"side-bar" 和那个 div 实际上是同一个元素。
让我们从 html 开始修复:
<!DOCTYPE html>
<html>
<head>
<title>Hello, World!</title>
<link rel="stylesheet" href="styles.css" />
<script src="script.js" type="text/javascript" charset="utf-8" defer>
</script>
</head>
<body>
<h1 class="title">Some content</h1>
<div id="false-sidebar" class="sidebar">
<button data-js-tag="detect-button-press">
show sidebar
</button>
</div>
<div data-js-tag="hidden-sidebar" id="hidden-sidebar" class="sidebar">
</div>
</body>
</html>
正如你所见,我添加了一个带有属性 id=“false-sidebar” 的 div(如名字所示,这是一个伪透明的侧边栏)以及其他 class="sidebar",并在里面放入一个带有属性 data-js-tag=“detect-button-press” 的按钮,它将负责显示side_bar
然后我们创建将作为边栏的元素,属性为 data-js-tag="hidden-sidebar"、id="hidden-sidebar" 和 class="sidebar"
在 css,我们添加:
.sidebar {
position: fixed;
left: 0;
top: 0;
}
#false-sidebar {
background-color: #03030313;
width: 20px;
height: 100vh;
}
我做了一个我认为正确的修改,但如果你愿意,可以通过把伪边栏做窄一点来还原它。
并修改:
.hidden-sidebar {
background-color: green;
}
以及对 .js 文件的更改。
// I've changed some of the names because
// I didn't think they were appropriate
let side_bar = document.querySelector("[data-js-tag='hidden-sidebar']");
let false_sidebar = document.getElementById( "false-sidebar" );
let showSidebarButton = false_sidebar.querySelector("[data-js-tag='detect-button-press']");
// we hide the button and the bar, and since we didn't set the
// size of the bar so that it wouldn't appear at startup,
// we'll do that here
showSidebarButton.classList.add( "hide" );
side_bar.classList.add( "hide" );
side_bar.style.width = `${100}px`;
side_bar.style.height = `${100}vh`;
// I've made a few minor changes so that the button
// appears below “mouse”
let moveButton = ( mousePosition = { x, y } ) => {
showSidebarButton.style.top = `${mousePosition.y - 10}px`;
showSidebarButton.style.left = `${mousePosition.x - 5}px`;
}
// when the mouse hovers over the *false-bar*, show us the button
false_sidebar.addEventListener( "mouseover", ( event ) => {
// although the call goes through, I haven't been able
// to get the button to appear in the right place
moveButton({x: event.x, y: event.y});
showSidebarButton.classList.remove( "hide" );
} );
// this method is necessary because the user might hover
// over the fake bar but not click the button.
false_sidebar.addEventListener( "mouseout", ( event ) => {
showSidebarButton.classList.add( "hide" );
} );
// when we leave the bar, we hide it
side_bar.addEventListener( "mouseleave", ( event ) => {
side_bar.classList.add( "hide" );
} );
// if we press the button, the bar appears
showSidebarButton.addEventListener( "click", ( event ) => {
side_bar.classList.remove( "hide" );
} );
现在,全部放在一起:
let side_bar = document.querySelector("[data-js-tag='hidden-sidebar']");
let false_sidebar = document.getElementById( "false-sidebar" );
let showSidebarButton = false_sidebar.querySelector("[data-js-tag='detect-button-press']");
showSidebarButton.classList.add( "hide" );
side_bar.classList.add( "hide" );
side_bar.style.width = `${100}px`;
side_bar.style.height = `${100}vh`;
let moveButton = ( mousePosition = { x, y } ) => {
showSidebarButton.style.top = `${mousePosition.y - 10}px`;
showSidebarButton.style.left = `${mousePosition.x - 5}px`;
}
false_sidebar.addEventListener( "mouseover", ( event ) => {
moveButton({x: event.x, y: event.y});
showSidebarButton.classList.remove( "hide" );
} );
false_sidebar.addEventListener( "mouseout", ( event ) => {
showSidebarButton.classList.add( "hide" );
} );
side_bar.addEventListener( "mouseleave", ( event ) => {
side_bar.classList.add( "hide" );
} );
showSidebarButton.addEventListener( "click", ( event ) => {
side_bar.classList.remove( "hide" );
} );
body {
padding: 25px;
background-color: #32442e;
padding: 0;
}
.title {
color: #a2a323;
}
button {
color: #a2a323;
background-color: #12141e;
}
#false-sidebar {
background-color: #03030313;
width: 20px;
height: 100vh;
}
#hidden-sidebar {
background-color: green;
}
.sidebar {
position: fixed;
left: 0;
top: 0;
}
.hide {
display: none;
}
.show-sidebar-button {
position: fixed;
}
<!DOCTYPE html>
<html>
<head>
<title>Hello, World!</title>
<link rel="stylesheet" href="styles.css" />
<script src="script.js" type="text/javascript" charset="utf-8" defer></script>
</head>
<body>
<h1 class="title">Some content</h1>
<div id="false-sidebar" class="sidebar">
<button data-js-tag="detect-button-press" class="hide show-sidebar-button">
show sidebar
</button>
</div>
<div data-js-tag="hidden-sidebar" id="hidden-sidebar" class="sidebar" >
</div>
</body>
</html>