有没有办法在不使用 Shadow DOM 的情况下向 <template> 添加类似 <slot> 的元素?

问题描述

为了遵守 DRY 原则,我想创建一个基于 <template>自定义组件。代码看起来像这样(请原谅我在通宵后在手机上打字时的切角):

@H_404_4@// base.html <template id="player"> <div class="card"> <div class="card-body"> <slot name="user-username"></slot> </div> </div> </template> // app.js class PlayerCard extends HTMLElement { constructor(){ super(); let tmpl = querySelector...; this.appendChild(tmpl.content.cloneNode(); } } define('player-card',PlayerCard); // index.html {% for user in users %} <player-card> <div slot="user-username">{{ user }}</div> </player-card> {% end for %}

但是在粉碎梦想和长时间的研究之后,我了解到插槽只能在 Shadow DOM 中使用。使用 SDOM 的问题是内部样式受到保护,不能直接受外部 CSS 影响。

这意味着,一方面,我不能将数据注入到模板实例中,也不能在不重新实现 Bootstrap 的情况下使用 Shadow DOM。

我被卡住了。对我的大脑来说,一定有办法让这个工作,但我的大脑找不到它——要么是因为它太复杂,要么是太琐碎和容易。

请问有什么建议吗?

解决方法

是的,<SLOT>s 只能在 shadowDOM 内部使用

但是您可以使用样式槽做更多的事情。

长答案见:::slotted CSS selector for nested children in shadowDOM slot

customElements.define('player-card',class extends HTMLElement {
    constructor() {
      let template = (id) => document.getElementById(id).content.cloneNode(true);
      super()
         .attachShadow({mode: 'open'})
         .append(template(this.nodeName));
      this.onclick = (evt) => this.style.color='blue';
    }
});
/* GLOBAL CSS */
player-card { /* inheritable styles trickle down into shadowDOM */
  font: 20px Arial;
  color: green;
}
[slot="username"] { /* lightDOM styles are REFLECTED to SLOTs */
  width: 200px;
  border: 2px solid green;
}
<template id="PLAYER-CARD">
  <style shadowDOM-CSS > 
    div { /* styles do not style content in SLOTs */
      padding: 1em;
      background:gold;
    }
    ::slotted(*) { /* slotted can only style the lightDOM 'skin' */
      background: lightgreen;
    }
  </style>
  <div>
    <slot name="username"></slot>
  </div>
</template>

<player-card>
    <!-- lightDOM,hidden when shadowDOM is used,then REFLECTED to SLOT -->
    <div slot="username">Ahmed</div>
</player-card>

<player-card>
    <!-- lightDOM,then REFLECTED to SLOT -->
    <div slot="username">Danny</div>
</player-card>