【问题标题】:Vanilla JavaScript event delegation when dealing with Web Components处理 Web 组件时的原生 JavaScript 事件委托
【发布时间】:2018-12-31 19:09:50
【问题描述】:

我当前的项目使用 Web 组件(自定义元素和 Shadow DOM),这使我能够将复杂的逻辑和样式封装在 Light DOM 之外。

不幸的是,我现在遇到了一个障碍,我需要能够随意切换元素,而无需取消绑定和重新绑定事件处理程序。

对我来说,这听起来像是事件委托的工作,所以我尝试将事件侦听器添加到 Light DOM 中的父节点,希望事件会从 Shadow DOM 中冒出来。

这似乎违背了 Shadow DOM 的封装,并且 event.target 始终是 ShadowRoot 而不是子级。

在这种情况下,我可以做些什么来允许经典事件委托?下面的代码 sn-p 显示了问题。我希望能够单击内部 DIV 并在单击事件处理程序中处理单击,但 event.target 始终是 custom-el

/* jshint esversion: 6 */

customElements.define('custom-el', class extends HTMLElement {

	constructor() {
		super();

		this._shadowRoot = this.attachShadow({
			mode: 'open'
		});

		const oInnerDiv = document.createElement('div');
		oInnerDiv.classList.add('inner');
    oInnerDiv.style.border = '2px solid blue';
    oInnerDiv.style.padding = '3rem';
		this._shadowRoot.appendChild(oInnerDiv);
	}

});

document.addEventListener('click', oEvent => {
	document.getElementById('result').innerText = oEvent.target.tagName;
}, true);
html {
	box-sizing: border-box;
}

*,
*::before,
*::after {
	box-sizing: inherit;
}

body {
	margin: 0;
	padding: 0;
}

main,
div,
custom-el {
	display: inline-block;
	border: 2px solid black;
	padding: 3rem;
}
<main>
    <custom-el>
</main>
  
<p id="result"></p>

【问题讨论】:

  • 我不知道它有多标准,但是您可以在 Chrome 中的 oEvent.path[0] 中访问它(其他浏览器是否支持 ShadowDOM?)
  • 我相信 Safari 确实如此,而 FF 在标志后面有它(由于 v63 中的标准化)。 Edge 尚无任何内容
  • AFK 现在。我再一次不知道标准。 FF 公开了一个Event.explicitOriginalTarget 属性,这可能会泄漏此信息?对于 Safari、IDK...
  • 你尝试过 Mid DOM 中介吗?

标签: javascript web-component shadow-dom event-delegation


【解决方案1】:

如果 shadow DOM 模式为open,则可以通过Event.composedPath() 方法获得点击的内部元素,该方法将返回交叉节点的数组(首先是内部节点)。

document.addEventListener('click', oEvent => {
    result.innerText = oEvent.composedPath()[0].tagName;
}, true);

此方法替换旧的Event.path 属性。

customElements.define('custom-el', class extends HTMLElement {
  constructor() {
    super();
    this._shadowRoot = this.attachShadow({ mode: 'open' });
    const oInnerDiv = document.createElement('div');
    oInnerDiv.classList.add('inner');
    oInnerDiv.style.border = '2px solid blue';
    oInnerDiv.style.padding = '1rem';
		this._shadowRoot.appendChild(oInnerDiv);      
  }
});

document.addEventListener('click', oEvent => {
  result.innerText = oEvent.composedPath()[0].tagName;
});
html {
	box-sizing: border-box;
}

*,
*::before,
*::after {
	box-sizing: inherit;
}

body {
	margin: 0;
	padding: 0;
}

main,
div,
custom-el {
	display: inline-block;
	border: 2px solid black;
	padding: 1rem;
}
<main>
    <custom-el></custom-el>
</main>
  
<p id="result"></p>

【讨论】:

    猜你喜欢
    • 2019-05-16
    • 1970-01-01
    • 1970-01-01
    • 2013-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多