在有插槽问题的 Web 组件中使用事件委托(冒泡)
Using event delegation (bubbling) in web component with slot problem
我创建了这个简单的例子(纯 JS,不在 Vue 或 React 等中):
<body>
<script>
(function () {
class MyComponent extends HTMLElement {
constructor() {
super();
const shadowRoot = this.attachShadow({ mode: 'open' });
const template = document.createElement('template');
template.innerHTML = `
<div>
<button>
<slot> <em>left</em> </slot>
</button>
</div>
`;
shadowRoot.append(template.content.cloneNode(true))
shadowRoot.addEventListener('click', (event) => {
// normal event delegation stuff,
const button = event.target.closest('button');
if (!button) return;
// do somthing with button
console.log(button);
});
}
}
customElements.define('my-component', MyComponent);
}());
</script>
<my-component id="myComponent"></my-component>
</body>
目前效果很好
但是,插槽添加后:
<my-component id="myComponent"> <span>previous</span> </my-component>
事件委托代码坏了,因为我点击的是光 DOM 而不是影 DOM,所以,我用 const button = event.target.closest('button');
得到了 null
有什么建议可以在槽内使用事件委托吗?
如果语法有问题,我是中国人:)
感谢阅读
event.composedPath()
输出包含 click
事件通过的所有元素。
跨越其间的所有 shadowRoot 边界。
我把你的代码压缩了位...
注意:SO 片段控制台速度慢且冗长;检查 TOP OF F12 控制台(SO 片段也可以在那里列出沙箱错误)
<script>
customElements.define('my-component',
class extends HTMLElement {
constructor() {
super()
.attachShadow({mode:'open'})
.innerHTML = `<div>
<button><slot>Left</slot></button>
</div>`;
this.shadowRoot.addEventListener('click', (evt) => {
console.log(evt.composedPath());
});
}
});
</script>
<my-component></my-component>
<my-component>Right</my-component>
我创建了这个简单的例子(纯 JS,不在 Vue 或 React 等中):
<body>
<script>
(function () {
class MyComponent extends HTMLElement {
constructor() {
super();
const shadowRoot = this.attachShadow({ mode: 'open' });
const template = document.createElement('template');
template.innerHTML = `
<div>
<button>
<slot> <em>left</em> </slot>
</button>
</div>
`;
shadowRoot.append(template.content.cloneNode(true))
shadowRoot.addEventListener('click', (event) => {
// normal event delegation stuff,
const button = event.target.closest('button');
if (!button) return;
// do somthing with button
console.log(button);
});
}
}
customElements.define('my-component', MyComponent);
}());
</script>
<my-component id="myComponent"></my-component>
</body>
目前效果很好
但是,插槽添加后:
<my-component id="myComponent"> <span>previous</span> </my-component>
事件委托代码坏了,因为我点击的是光 DOM 而不是影 DOM,所以,我用 const button = event.target.closest('button');
有什么建议可以在槽内使用事件委托吗?
如果语法有问题,我是中国人:) 感谢阅读
event.composedPath()
输出包含 click
事件通过的所有元素。
跨越其间的所有 shadowRoot 边界。
我把你的代码压缩了位...
注意:SO 片段控制台速度慢且冗长;检查 TOP OF F12 控制台(SO 片段也可以在那里列出沙箱错误)
<script>
customElements.define('my-component',
class extends HTMLElement {
constructor() {
super()
.attachShadow({mode:'open'})
.innerHTML = `<div>
<button><slot>Left</slot></button>
</div>`;
this.shadowRoot.addEventListener('click', (evt) => {
console.log(evt.composedPath());
});
}
});
</script>
<my-component></my-component>
<my-component>Right</my-component>