javascript - 在 Shadow DOM 中的 setTimeout 中的 event.target 发生了变化?
问题描述
https://jsbin.com/qogewowomi/1/edit?html,js,输出
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<test-test></test-test>
<button id='out'>Outside Shadow DOM</button>
</body>
</html>
customElements.define('test-test', class extends HTMLElement {
constructor() {
super();
const node = document.createElement('template');
node.innerHTML = '<button id="in">Inside Shadow DOM</button>';
this.attachShadow({
mode: 'open'
}).appendChild(node.content);
this.shadowRoot.querySelector('#in').addEventListener('click', e => {
console.log(e.target);
setTimeout(() => {
console.log(e.target);
});
});
}
});
document.querySelector('#out').addEventListener('click', e => {
console.log(e.target);
setTimeout(() => {
console.log(e.target);
});
});
我在 shadow DOM 内外的事件侦听器中发现了这些不一致的行为。Inside Shadow DOM
单击按钮时,控制台输出:
<button id="in">Inside Shadow DOM</button>
<test-test>...</test-test>
Outside Shadow DOM
单击按钮时,控制台输出:
<button id="out">Outside Shadow DOM</button>
<button id="out">Outside Shadow DOM</button>
在 Chrome、FireFox 和 Safari 中测试。他们都有这些不一致的行为。我不知道这是预期的行为还是错误?
更新:这个问题不应该被关闭。另一个没有回答这个问题。
解决方案
这是预期的行为,而不是错误。
解释它需要太多的字符。
看:
- 事件 currentTarget 在 setTimeout 之后发生变化
- https://javascript.info/shadow-dom-events
- https://dom.spec.whatwg.org/#dispatching-events
- https://developer.mozilla.org/en-US/docs/Web/API/Event/Comparison_of_Event_Targets
用我简单的话来说:
Javascript是单线程的。
(e)Event
是一个在所有事件处理程序中传递的全局对象
当您使用 SetTimeout 时,Event
内容可以/将会有所不同
我重写了你的测试代码:https ://jsfiddle.net/CustomElementsExamples/wj1234km/
<shadow-element id="lightcoral" title=One></shadow-element>
<script>
function log(label, color, scope, evt) {
let composedTarget = (evt.composed && evt.composedPath());
console.log(`%c ${label} \t%c ${evt.target.id} `, `background:${color}`, `background:${evt.target.id};color:white`, '\n\ttarget:', evt.target, "\n\tthis:", scope.nodeName || "window", "\n\tcurrentTarget", evt.currentTarget, '\n\tclickedTarget:', evt.clickedTarget, "\n\tcomposed:", evt.composed ? "True" : "False", "composedPath[0]:", composedTarget[0]);
}
customElements.define('shadow-element', class extends HTMLElement {
constructor() {
super().attachShadow({mode:'open'})
.innerHTML = `<button id=green>click ${this.title}</button>`;
let button = this.shadowRoot.querySelector('button');
button.onclick = e => {
let savedTarget = e.target;
e.clickedTarget = e.target;
button.onclick = false; //prevent double capture
log(`clicked element:${this.id}`, 'lightgreen', this, e);
setTimeout(() => {
log('timeout element', 'red;color:yellow', this, e)
}, 500);
};
//this.onclick = button.onclick;
}
});
</script>
输出:
target
now 是<shadow-element>
因为一旦setTimeout
运行,全局事件就一直向上传递到 DOM。
currentTarget
告诉你所有事件处理完成
https://developer.mozilla.org/en-US/docs/Web/API/Event/currentTarget
clickedTarget
演示您可以在该全局Event 对象(被传递)上设置自定义属性。从而“保存”您单击的目标。但是.. 其他事件(或下面的 element.onclick 函数调用)可能会覆盖它,因此最好在正确的范围内设置自定义变量,并在您的savedTarget
setTimeout
target
您可以通过在元素本身上设置单击处理程序来查看更改方式。
target
成为<shadow-element>
事件冒泡 DOM 并“逃脱”shadowDOM 的那一刻
推荐阅读
- java - 您可以使用 WiFiNetworkSpecifier 连接到您的 Android 设备在 Android Q 上记住的 WPA 网络吗
- c# - unity Assets\script\Produce.cs(10,20): 错误 CS1002: ; 预期分辨率
- java - 用逗号分隔的 CSV 文件列数据在 Excel(JAVA)中打开时显示为数字
- cordova - Ionic cordova 运行相当于 Capacitor 项目的浏览器
- excel - 太多的 Power Queries 让我内存不足 - 还有其他方法可以做到这一点吗?
- django-models - django 添加另一种类型的角色,例如 request.user.is_newrole
- node.js - 为什么邮递员显示错误消息但反应应用程序没有显示它?
- python-3.x - 有没有办法解决 ContextDecorator 中的 __enter__ AttributeError?
- excel - 计算excel中的工作日数
- android - Jetpack Compose:无法在 TextField 中显示文本