是否可以自动或以编程方式slot
放置嵌套的Web组件或特定类型的元素,而不必在其上指定属性?
考虑这样的一些结构:
<parent-element>
<child-element>Child 1</child-element>
<child-element>Child 2</child-element>
<p>Content</p>
</parent-element>
随着<parent-element>
有阴影DOM是这样的:
<div id="child-elements">
<slot name="child-elements">
<child-element>Default child</child-element>
</slot>
</div>
<div id="content">
<slot></slot>
</div>
预期结果是:
<parent-element>
<#shadow-root>
<div id="child-elements">
<slot name="child-elements">
<child-element>Child 1</child-element>
<child-element>Child 2</child-element>
</slot>
</div>
<div id="content">
<slot>
<p>Content</p>
</slot>
</div>
</parent-element>
换句话说,我要强制执行<child-element>
s仅在<parent-element>
与<td>
元素内类似的情况下才被允许<tr>
。我希望将它们放置在<slot name="child-elements">
元素中。必须slot
为它们中的每一个都指定一个属性,以将它们放置在<parent-element>
似乎特定的插槽中。同时,内的其余内容<parent-element>
应自动放入第二个<slot>
元素中。
我首先搜索了一种在注册父元素时定义此方法的方法,尽管CustomElementRegistry.define()
当前仅支持此功能extends
。
然后我想,也许有一个功能允许手动放置元素,例如childElement.slot('child-elements')
,但是似乎不存在。
然后,我尝试在父元素的构造函数中以编程方式实现此目的,如下所示:
constructor() {
super();
this.attachShadow({mode: 'open'});
this.shadowRoot.appendChild(template.content.cloneNode(true));
const childElements = this.getElementsByTagName('child-element');
const childElementSlot = this.shadowRoot.querySelector('[name="child-elements"]');
for (let i = 0; i < childElements.length; i++) {
childElementSlot.appendChild(childElements[i]);
}
}
尽管这不会将子元素移动到<slot name="child-elements">
,所以所有子元素仍会插入第二个<slot>
元素中。
您未命名的默认设置<slot></slot>
将捕获所有未分配给命名插槽的元素;
因此,slotchange
事件可以捕获这些事件并强制child-element
插入正确的插槽:
customElements.define('parent-element', class extends HTMLElement {
constructor() {
super().attachShadow({mode:'open'})
.append(document.getElementById(this.nodeName).content.cloneNode(true));
this.shadowRoot.addEventListener("slotchange", (evt) => {
if (evt.target.name == "") {// <slot></slot> captures
[...evt.target.assignedElements()]
.filter(el => el.nodeName == 'CHILD-ELEMENT') //process child-elements
.map(el => el.slot = "child-elements"); // force them to their own slot
} else console.log(`SLOT: ${evt.target.name} got:`,evt.target.assignedNodes())
})}});
customElements.define('child-element', class extends HTMLElement {
connectedCallback(parent = this.closest("parent-element")) {
// or check and force slot name here
if (this.parentNode != parent) {
if (parent) parent.append(this); // Child 3 !!!
else console.error(this.innerHTML, "wants a PARENT-ELEMENT!");
}}});
child-element { color: red; display: block; } /* style lightDOM in global CSS! */
<template id=PARENT-ELEMENT>
<style>
:host { display: inline-block; border: 2px solid red; }
::slotted(child-element) { background: lightgreen }
div { border:3px dashed rebeccapurple }
</style>
<div><slot name=child-elements></slot></div>
<slot></slot>
</template>
<parent-element>
<child-element>Child 1</child-element>
<child-element>Child 2</child-element>
<b>Content</b>
<div><child-element>Child 3 !!!</child-element></div>
</parent-element>
<child-element>Child 4 !!!</child-element>
请注意,处理<child-element>
不是的直接子代的逻辑<parent-element>
,您可能需要根据自己的需要重写它
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句