为什么 customElements.upgrade 似乎没有升级此自定义元素?

Why does customElements.upgrade appear to not upgrade this custom element?

我的情况类似于下面的示例:从 template 元素,我克隆了一个包含自定义元素的节点树。一个自定义元素在初始化期间传递数据,此处由 infobox.setData(getData()) 行表示。我用来传递数据的函数 (setData) 是由我的自定义 class 添加的,因此我通过将节点树传递给 customElements.upgrade 来确保自定义元素在调用它之前已升级. (我也试过通过 infobox 本身。)

不幸的是,当我尝试 运行 我的代码或下面的示例时,我收到错误 infobox.setData is not a function。我已经确认 infobox instanceof InfoBox 是错误的,并且该元素在连接到文档之前没有自定义属性或方法,因此 customElements.upgrade 似乎没有升级树中的元素。是什么阻止了它这样做?

document.getElementById('addWidgetErr').onclick = addWidgetErr
document.getElementById('addWidgetWorkaround').onclick = addWidgetWorkaround

class InfoBox extends HTMLElement {
  _data = ""

  connectedCallback() {
    this.render()
  }

  setData(val) {
    this._data = val
    this.render()
  }

  render() {
    if (!this?.isConnected) {
      return
    }

    this.replaceChildren(...this._data.split(' ').map(datum => {
      const el = document.createElement('span')
      el.innerText = datum
      return el
    }))
  }
}
customElements.define('info-box', InfoBox)

function addWidgetErr() {
  const widget = document.getElementById('widgetTemplate').content.cloneNode(true)
  const infobox = widget.querySelector('info-box')

  // From my understanding, this should convert all unknown elements in `widget`
  //   into custom elements.
  customElements.upgrade(widget)

  console.assert(!(infobox instanceof InfoBox))
  console.assert(!('setData' in infobox))
  // TypeError: infobox.setData is not a function
  infobox.setData(getData())

  document.getElementById('container').append(widget)
}

function addWidgetWorkaround() {
  const widget = document.getElementById('widgetTemplate').content.cloneNode(true)
  const infobox = widget.querySelector('info-box')

  document.getElementById('container').append(widget)

  // works because infobox has been upgraded after being added to the document
  infobox.setData(getData())
}

function getData() {
  return ('lorem ipsum dolor sit amet consectetur adipiscing elit proin at ' +
    'vestibulum enim vestibulum ante ipsum primis in faucibus orci luctus')
}
#container {
  background: lightgrey;
  padding: 2em;
}

info-box {
  display: flex;
  flex-flow: row wrap;
  gap: .5em;
  padding: .5em;
  background: darkgrey;
}

info-box>span {
  background: lightblue;
  border-radius: .5em;
  padding: .5em;
}
<template id="widgetTemplate">
    <details>
        <info-box></info-box>
    </details>
</template>

<button id="addWidgetErr">Add via `upgrade`</button>
<button id="addWidgetWorkaround">Add post-hoc</button>
<div id="container"></div>

我缩小到 <template> / cloneNode

在这里提交:https://github.com/WICG/webcomponents/issues
(如果它是一个错误,你的学分,换句话说 我没有线索 :-)

class myEl extends HTMLElement {}

let el1 = document.createElement("my-el");
let el2 = Object.assign(document.createElement("template"), {
            innerHTML: "<my-el></my-el>"
          }).content.cloneNode(true).querySelector("my-el");

customElements.define("my-el", myEl);

customElements.upgrade(el1); // works as documented
customElements.upgrade(el2); // doesn't upgrade!

console.assert(el1 instanceof myEl, "element not upgraded");
console.assert(el2 instanceof myEl, "template not upgraded");