javascript 创建的模板元素不起作用

javascript created template element not working

如果我手动将 template 节点写入 HTML,我就可以在我的自定义元素中使用它了。如果我创建一个 template 节点并在我尝试使用它时使用 javascript 将其附加到 HTML,它是空的...

在下面的示例中,我将 template-a 设置为常规 HTML 方式,并使用 javascript 将 template-b 设置为相同的形状。我定义了一个使用两个模板的非常简单的自定义元素。只有 template-a 可见。

const sandbox = document.getElementById('sandbox')

const slot = document.createElement('slot')
slot.setAttribute('name', 'b')
slot.append('slot content goes here')
const em = document.createElement('em')
em.append(slot, '?')
const createdTemplate = document.createElement('template')
createdTemplate.setAttribute('id', 'template-b')
createdTemplate.append(em)
sandbox.append(createdTemplate)

customElements.define('test-element', class extends HTMLElement {
  constructor () {
    super()
    this.attachShadow({ mode: 'open' }).append(
      ...['template-a','template-b']
      .map(id =>
        document.getElementById(id).content.cloneNode(true)
      )
    )
  }
})
<div id="sandbox">
  <template id="template-a">
    <strong><slot name="a">slot content goes here</slot>!</strong>
  </template>
  <test-element>
    <span slot="a">some a slot content</span>
    <span slot="b">some b slot content</span>
  </test-element>
</div>

template 节点有一个特殊的 content 属性来保存它们的子节点。 (我有点知道,但认为它比实际情况更神奇)。如果这一行:

createdTemplate.append(em)

改为

createdTemplate.content.append(em)

然后一切正常

const sandbox = document.getElementById('sandbox')

const slot = document.createElement('slot')
slot.setAttribute('name', 'b')
slot.append('slot content goes here')
const em = document.createElement('em')
em.append(slot, '?')
const createdTemplate = document.createElement('template')
createdTemplate.setAttribute('id', 'template-b')
createdTemplate.content.append(em)
sandbox.append(createdTemplate)

customElements.define('test-element', class extends HTMLElement {
  constructor () {
    super()
    this.attachShadow({ mode: 'open' }).append(
      ...['template-a','template-b']
      .map(id =>
        document.getElementById(id).content.cloneNode(true)
      )
    )
  }
})
<div id="sandbox">
  <template id="template-a">
    <strong><slot name="a">slot content goes here</slot>!</strong>
  </template>
  <test-element>
    <span slot="a">some a slot content</span>
    <span slot="b">some b slot content</span>
  </test-element>
</div>

关于您的代码的一些注释:

this.shadowRoot

this.shadow = this.attachShadow({ mode: 'open' })

可以变成

this.attachShadow({ mode: 'open' })

这个creates/setsthis.shadowRoot免费

appendChild 与 append

注意 .appendChild(el) 取一个元素

.append()接受一个数组

唯一的区别是appendChild()returns对插入元素的引用,
append() returns 什么都没有

所以你可以这样写:

em.appendChild(slot)
em.appendChild(document.createTextNode('?'))

作为

em.append(slot, document.createTextNode('?'))

如果数组中有节点:

let myElements = [slot, document.createTextNode('?')];

你可以使用 ES6 扩展运算符:

em.append(...myElements)

这意味着你可以写:

this.shadow.appendChild(document.getElementById('template-a').content.cloneNode(true))
this.shadow.appendChild(document.getElementById('template-b').content.cloneNode(true))

如:

this.shadowRoot
 .append(
   ...['a','b']
      .map(templ => document.getElementById(`template-${templ}`).content.cloneNode(true))
  )