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

时间:2016-05-22 02:31:21

标签: javascript shadow-dom

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

我想写一些类似的东西:

window.addEventListener('mousedown', function (evt) {
  if (!componentNode.contains(evt.target)) {
    closeDropdown();
  }
});

但是,该事件已重新定位,因此evt.target 总是在元素外部。事件在到达窗口之前会有多个阴影边界,因此似乎无法真正了解用户是否在组件内部单击。

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

3 个答案:

答案 0 :(得分:6)

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

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

如果有人知道Event.path的实际规格参考(如果链接的规格页已经没有了),请随时对其进行编辑。

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

演示:点击菜单展开,点击菜单项以外的任何地方都会关闭菜单。



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");
  }
});
&#13;
#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;
}
&#13;
<div id="host"></div>
&#13;
&#13;
&#13;

答案 1 :(得分:1)

event.target的{​​{1}}将是shadowRoot元素。要关闭host中的<select>元素,如果shadowDOM不是event.target元素,则可以使用host,然后在if (evt.target !== hostElement)上致电.blur() }

hostElement
var input = document.querySelector("input");
var shadow = input.createShadowRoot();
var template = document.querySelector("template");
var clone = document.importNode(template.content, true);
shadow.appendChild(clone);

window.addEventListener("mousedown", function (evt) {
  if (evt.target !== input) {
    input.blur();
  }
});

答案 2 :(得分:0)

另一种选择是检查事件光标相对于目标元素的偏移量:

listener(event) {
    const { top, right, bottom, left } = targetElement.getBoundingClientRect();
    const { pageX, pageY } = event;
    const isInside = pageX >= left && pageX <= right && pageY >= top && pageY <= bottom;
}