问题描述
class RepeatMe extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
let slot = document.createElement('slot');
slot.setAttribute('name','bar');
this.shadowRoot.append(slot);
slot = document.createElement('slot');
slot.setAttribute('name','content');
this.shadowRoot.append(slot);
slot = document.createElement('slot');
slot.setAttribute('name','bar');
this.shadowRoot.append(slot);
}
}
window.customElements.define('repeat-me',RepeatMe);
我使用它如下:
<repeat-me>
<div slot="bar">I'm a bar</div>
<div slot="content">I'm some content</div>
</repeat-me>
我想在 shadow dom 中重复插槽 bar
(因为开头和结尾的内容相同),但我得到的是只有第一个插槽被渲染并且第二个是空的。我正在尝试使用 shadow dom 插槽做些什么,或者您知道某种方法可以实现这样的目标吗?
解决方法
不,插槽是独一无二的,
并且多个 lightDOM 元素可以插入到同一个 SLOT
将 SLOT 视为您的邮箱;您是否希望您的邮件总是复制到另一个邮箱?
如果你有这个要求,你需要一个过滤器来复制电子邮件(或插槽内容)
WebComponents 有 2 个复制选项:
-
将
<span slot="bar">
克隆到 shadowRoot 中的其他(非插槽)DOM 元素 -
克隆到新的 lightDOM 元素
<span slot="duplicate_bar1">
用于新插入的内容
下面的代码为 slotchange
上发生的 <span slot="bar">
事件提供了两个选项(槽中的新内容)
-
在
slotchange
上,插槽内容被克隆到class="duplicate_bar"
(let dups = ...
) -
在
slotchange
上创建新的 lightDOM 元素 (let dupslots = ...
)
请注意,只有方法 2. 使用 <slot>
功能,您可以使用 :slotted
样式
此代码仅复制内容;它不会清理已删除的 SLOT 内容。
<my-element>
<span slot="bar"> ONE </span>
<span slot="bar"> TWO </span>
<span slot="content"> content </span>
</my-element>
<template id="MY-ELEMENT">
<style>
::slotted(*) { background: lightgreen }
</style>
slot bar: <slot name="bar"></slot>
<br> slot: content: <slot name="content"></slot>
<br>Duplicate in SPAN: <span class="duplicate_bar"></span>
<br>Duplicate in B:<b class="duplicate_bar"></b>
<br>duplicate_bar1:<slot name="duplicate_bar1"></slot>
<br>duplicate_bar2:<slot name="duplicate_bar2"></slot>
</template>
<script>
customElements.define('my-element',class extends HTMLElement {
constructor() {
let template = id => document.getElementById(id).content.cloneNode(true);
super().attachShadow({mode: 'open'}).append(template(this.nodeName));
let slotname = "bar";
let slot = this.shadowRoot.querySelector(`[name="${slotname}"]`);
slot.addEventListener("slotchange",(evt) => {
let assigned = slot.assignedNodes();
let dups = [...this.shadowRoot.querySelectorAll(".duplicate_" + slotname)];
let dupslots = [...this.shadowRoot.querySelectorAll(`slot[name*="duplicate_bar"]`)];
assigned.forEach(node => {
dups.forEach(el => el.append(node.cloneNode(true)));
dupslots.forEach(duplicateslot => {
let newNode = node.cloneNode(true);
newNode.slot = duplicateslot.name; // set BEFORE adding to DOM! otherwise 'bar' slotchange Events triggers on it
this.append(newNode);
})
});
});
}
});
</script>