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