Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/image/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 确定用户是否在阴影dom外部单击_Javascript_Shadow Dom - Fatal编程技术网

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

Javascript 确定用户是否在阴影dom外部单击,javascript,shadow-dom,Javascript,Shadow Dom,我正在尝试实现一个下拉列表,你可以点击外部关闭。下拉列表是自定义日期输入的一部分,封装在输入的阴影DOM中 我想写一些像: window.addEventListener('mousedown', function (evt) { if (!componentNode.contains(evt.target)) { closeDropdown(); } }); 但是,事件是重定目标的,因此evt.target始终位于元素外部。事件在到达窗口之前将跨越多个阴影边界,因此似乎无法真

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

我想写一些像:

window.addEventListener('mousedown', function (evt) {
  if (!componentNode.contains(evt.target)) {
    closeDropdown();
  }
});
但是,事件是重定目标的,因此
evt.target
始终位于元素外部。事件在到达窗口之前将跨越多个阴影边界,因此似乎无法真正知道用户是否在我的组件内单击


注意:我没有在任何地方使用polymer——我需要一个适用于通用shadow DOM的答案,而不是特定于polymer的hack。

您可以尝试使用
事件的
path
属性。还没有找到它的实际引用,MDN也没有它的页面。不过在shadowdom教程中有一小部分是关于它的。因此,我不知道跨浏览器的兼容性

找到了about事件路径,不确定这是否是针对
event.path
属性的,但它是我能找到的最接近的引用

如果有人知道对
Event.path
的实际规范引用(如果链接的规范页面还没有),请随时在中编辑它

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

演示:单击菜单展开,单击菜单项以外的任何位置将关闭菜单

var-host=document.querySelector(“#host”);
var root=host.createShadowRoot();
d=document.createElement(“div”);
d、 id=“shadowdiv”;
d、 innerHTML=`
菜单
项目1
项目2
项目3
其他阴影元素
`;
var menuToggle=d.querySelector(“菜单切换”);
var menu=d.querySelector(“菜单”);
menuToggle.addEventListener(“单击”,函数(e){
menu.classList.toggle(“活动”);
});
root.appendChild(d)
//使用文档而不是窗口
文档.添加的列表器(“单击”,函数(e){
如果(!menu.contains(e.path[0])){
menu.classList.remove(“活动”);
}
});
#主机::阴影#菜单{
高度:24px;
宽度:150px;
过渡:高度1s;
溢出:隐藏;
背景:黑色;
颜色:白色;
}
#主机::shadow#menu.active{
高度:300px;
}
#主机::阴影#菜单。菜单项{
高度:24px;
文本对齐:居中;
线高:24px;
}
#主持人:影子#其他{
位置:绝对位置;
右:100px;
顶部:0px;
背景:黄色;
宽度:100px;
高度:32px;
字体大小:12px;
填充:4px;
}

事件。
shadowRoot
目标将是
主机
元素。若要关闭
shadowDOM
中的
元素(如果
event.target
不是
host
元素),可以使用
if(evt.target!==hostElement)
,然后在
hostElement
上调用
.blur()

var input=document.querySelector(“input”);
var shadow=input.createShadowRoot();
var template=document.querySelector(“模板”);
var clone=document.importNode(template.content,true);
shadow.appendChild(克隆);
window.addEventListener(“鼠标向下”,函数(evt){
如果(evt.target!==输入){
input.blur();
}
});

1999
2000

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

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

const isInside=pageX>=left&&pageX=top&&pageY…将是
窗口
,因为我正在将事件侦听器添加到窗口中。我们可以用小提琴/示例吗?会有帮助的!“在到达窗口之前,事件将跨越多个阴影边界,因此似乎无法真正知道用户是否在我的组件内单击。"如果单击,则
事件.target
将是
主机
元素注意,因为
宽度
窗口
宽度
,如果单击发生在
右侧,则
控制台
@guest271314会记录
true
,这实际上是预期的,因为这是内部的
div
阴影根,所以
shadowRoot.contains()
将为此返回true。添加了一个实际元素的日志,以显示实际元素的divinside@guest271314,修改了示例,以显示更多我认为OP的用途。在代码段中,单击除菜单项以外的任何项都将关闭菜单。如果它们使用
event.target
,因为它被重定向到主机,您不会e能够区分菜单项和阴影dom中的任何其他元素。@PatrickEvans现在,您可以使用
Event.composedPath
。请参阅dom标准中的:“返回事件路径的项对象(将调用侦听器的对象),阴影树中阴影根模式为无法从事件的currentTarget访问的“closed”如果只有一层阴影DOM,则事件将重定目标到宿主元素。但是,如果宿主元素位于另一个元素的阴影DOM中,则在到达文档/窗口上的事件处理程序之前,事件将重定目标两次。如果我不清楚,请原谅。