【问题标题】:javascript created template element not working [duplicate]javascript创建的模板元素不起作用[重复]
【发布时间】:2019-12-22 07:19:13
【问题描述】:

如果我手动将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>

【问题讨论】:

  • 嗯,这很尴尬......我在发布这个之前搜索了一天,是的,有一个现有的答案,这正是我想要的

标签: javascript web-component


【解决方案1】:

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

this.shadowRoot

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

可以变成

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

这会免费创建/设置this.shadowRoot

appendChild 与追加

注意.appendChild(el) 需要一个元素

.append() 需要一个数组

唯一的区别是appendChild() 返回对插入元素的引用,
append() 什么也不返回

所以你可以写:

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))
  )

【讨论】:

  • 我发现了(与之碰撞)shadowRoot 的东西,但从来没有费心去看看它是镀铬的还是通用的。我现在认为它是标准的和惯用的:)
  • 感谢关于更具表现力的节点构建的想法,我一定会在我的项目中使用它们。示例代码故意有点迂腐,但我认为您的想法不会损害可读性;如果相反的话。
  • (编辑了我的问题和答案以包含您的建议)
【解决方案2】:

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>

【讨论】:

    猜你喜欢
    • 2014-11-04
    • 2013-02-05
    • 1970-01-01
    • 2016-08-18
    • 2011-02-10
    • 1970-01-01
    • 1970-01-01
    • 2015-10-23
    • 1970-01-01
    相关资源
    最近更新 更多