确定用户是否在阴影dom外部单击

ova*_*gle 8 javascript shadow-dom

我正在尝试实现一个下拉菜单,你可以点击外面关闭.下拉列表是自定义日期输入的一部分,并封装在输入的shadow DOM中.

我想写一些类似的东西:

window.addEventListener('mousedown', function (evt) {
  if (!componentNode.contains(evt.target)) {
    closeDropdown();
  }
});
Run Code Online (Sandbox Code Playgroud)

然而,该事件被重新定向,所以evt.target永远的元素之外.事件在到达窗口之前会有多个阴影边界,因此似乎无法真正了解用户是否在组件内部单击.

注意:我没有在任何地方使用聚合物 - 我需要一个适用于通用阴影DOM的答案,而不是聚合物特定的黑客.

Pat*_*ans 6

您可以尝试使用对象的path属性event.没有找到它的实际参考,MDN还没有它的页面.HTML5Rocks有一个关于它的小部分,但有阴影dom教程.因此,我不知道跨浏览器的兼容性.

找到关于事件路径的W3 Spec,不确定这是否与该Event.path属性完全相同,但它是我能找到的最接近的参考.

如果有人知道实际的规范引用Event.path(如果链接的规范页面不是它),可以随意编辑它.

它保留了事件经历的路径.它将包含阴影dom中的元素.list(path[0])中的第一个元素应该是实际单击的元素.请注意,您需要contains从阴影dom参考调用,例如阴影dom中的shadowRoot.contains(e.path[0])某个子元素.

演示:单击菜单展开,单击任意位置除菜单项将关闭菜单.

var host = document.querySelector('#host');
var root = host.createShadowRoot();
d = document.createElement("div");
d.id = "shadowdiv";

d.innerHTML = `
  <div id="menu">
    <div class="menu-item menu-toggle">Menu</div>
    <div class="menu-item">Item 1</div>
    <div class="menu-item">Item 2</div>
    <div class="menu-item">Item 3</div>
  </div>
  <div id="other">Other shadow element</div>
`;
var menuToggle = d.querySelector(".menu-toggle");
var menu = d.querySelector("#menu");
menuToggle.addEventListener("click",function(e){
  menu.classList.toggle("active");
});
root.appendChild(d)

//Use document instead of window
document.addEventListener("click",function(e){
  if(!menu.contains(e.path[0])){
    menu.classList.remove("active");
  }
});
Run Code Online (Sandbox Code Playgroud)
#host::shadow #menu{
  height:24px;
  width:150px;
  transition:height 1s;
  overflow:hidden;
  background:black;
  color:white;
}
#host::shadow #menu.active {
  height:300px;
}
#host::shadow #menu .menu-item {
  height:24px;
  text-align:center;
  line-height:24px;
}

#host::shadow #other {
  position:absolute;
  right:100px;
  top:0px;
  background:yellow;
  width:100px;
  height:32px;
  font-size:12px;
  padding:4px;
}
Run Code Online (Sandbox Code Playgroud)
<div id="host"></div>
Run Code Online (Sandbox Code Playgroud)

  • @PatrickEvans 现在,您可以使用`Event.composedPath`。参见DOM标准中的[`Event`接口](https://dom.spec.whatwg.org/#interface-event):*“返回事件路径的项目对象(将调用侦听器的对象),除了影子树中的任何节点,其影子根的模式为“关闭”,并且无法从事件的 currentTarget 到达。”* (2认同)

小智 6

由于声誉无法发表评论,但想分享它应该如何使用composedPath. 请参阅确定用户是否在 Shadow dom 外部单击

document.addEventListener("click",function(e){
  if(!e.composedPath().includes(menu)){
    menu.classList.remove("active");
  }
});
Run Code Online (Sandbox Code Playgroud)