如何在需要检测鼠标悬停的元素下方仍然允许指针事件?(dHTML)

前端开发 2026-07-10

概览

在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>
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章