为什么 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");
我的情况类似于下面的示例:从 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");