认识<slot>——具名插槽

279 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第7天,点击查看活动详情

  • 使用Slot可以在单个实例中通过声明式的语法展示不同的文本
  • 没有template元素也是可以使用slot的
  • 能被插入到插槽内的元素称之为Slotable,已经被插入到插槽内的元素称之为Slotted

具名插槽

  • <slot>元素内可以添加默认结构,当不存在对应名称从带有slot属性的元素时,会显示该结构。
    <template id="slot-test">
        <p>
            <slot name="slotable-test">
                这里是默认文字,当该该插槽没有被使用时,插槽位置显示默认结构
            </slot>
        </p>
     </template>
  • 同一个名称的<slot>可以插入多个结构,也就是说,多个元素的slot元素为同名时,会被依次插入<slot>的位置
      <slot-test>
          <div slot="slotable-test">
              这里是使用插槽后的元素,带有slot的元素会被插入对应插槽
          </div>
          <div slot="slotable-test">
              同一个名字的插槽可以插入多个带有slot的元素
          </div>
      </slot-test>
  • 只能在顶层子元素中使用slot元素,非顶层子元素使用slot属性会被忽略,如下面代码所示,在div中嵌套的div带有slot属性,但并不会被插入到对应位置。
      <slot-test>
          <div>
              <div slot="slotable-test">
                仅仅顶层子元素可以设置slot,其他子元素设置会被忽略,该段文字在非顶层子元素,不会显示
              </div>
          </div>
      </slot-test>
  • 完整代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <template id="slot-test">
        <p><slot name="slotable-test">这里是默认文字,当该该插槽没有被使用时,插槽位置显示默认结构</slot></p>
      </template>
      <slot-test>
          <div class="slot" slot="slotable-test">这里是使用插槽后的元素,带有slot的元素会被插入对应插槽</div>
          <div class="slot" slot="slotable-test">同一个名字的插槽可以插入多个带有slot的元素</div>
          <div>
            <div class="slot" slot="slotable-test">仅仅顶层元素可以设置slot,子元素设置会被忽略,该段文字在子元素,不会显示</div>
          </div>
      </slot-test>
</body>
<script>
customElements.define('slot-test',
  class extends HTMLElement {
    constructor() {
      super();
      let template = document.getElementById('slot-test');
      let templateContent = template.content;
​
      const shadowRoot = this.attachShadow({mode: 'open'})
        .appendChild(templateContent.cloneNode(true));
  }
})
</script>
</html>
  • 从下图我们可以看到渲染结果,可以看到带有slot属性的元素的结构并未被真实的插入到对应位置,而是在对应位置创建了一个映射。那么CSS和JavaScript的行为又是怎么样的呢

slot-name.png

  • 使用JavaScript选择器
let num1 = document.querySelectorAll("slot-test .slot").length
console.log(num1)   //3
let num2 = document.querySelectorAll("p .slot").length
console.log(num2)   //0
  • 使用CSS
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<style>
    .slot{
        color: red;
    }
</style>
<body>
    <template id="slot-test">
        <style>
            .slot{
                color: blue;
            }
            p{
                color: brown;
            }
        </style>
        <p><slot name="slotable-test">这里是默认文字,当该该插槽没有被使用时,插槽位置显示默认结构</slot></p>
      </template>
      <slot-test>
          <div class="slot" slot="slotable-test">这里是使用插槽后的元素,带有slot的元素会被插入对应插槽</div>
          <div class="slot" slot="slotable-test">同一个名字的插槽可以插入多个带有slot的元素</div>
          <div>
            <div class="slot" slot="slotable-test">仅仅顶层元素可以设置slot,子元素设置会被忽略,该段文字在子元素,不会显示</div>
          </div>
      </slot-test>
</body>
<script>
customElements.define('slot-test',
  class extends HTMLElement {
    constructor() {
      super();
      let template = document.getElementById('slot-test');
      let templateContent = template.content;
      const shadowRoot = this.attachShadow({mode: 'open'})
        .appendChild(templateContent.cloneNode(true));
  }
})
</script>
</html>

slot-text.png

可以看到,文字的颜色为红色,仅仅在渲染结构的改变了,由于在文档内节点仍然没有改变,外层的CSS渲染和JS控制仍然是可以控制的,且在shadow dom内无法使用.slot的className进行样式渲染,生效的属性为light tree中的style样式。