【发布时间】:2016-08-28 22:51:40
【问题描述】:
我有一个元素的引用,该元素将在某个时候升级为自定义元素。如何等待它升级?
例如,假设el 是引用。如果假设它为此目的附加了一个承诺,则代码可能类似于
await el.upgradePromise
// do something after it has been upgraded.
这当然不存在,但描述了我想要做什么。也许没有轮询就没有办法做到这一点?如果我使用轮询,我会轮询什么(假设我没有对应该升级到的类构造函数的引用)。也许我可以轮询el.constructor 并等待它不是HTMLElement,或者等待它不是HTMLUnknownElement?
编辑:对于背景,我有一些类似以下的代码,其中使用 setTimeout 是为了让代码正常工作。第一个console.log 输出假,而超时的输出真。
import OtherElement from './OtherElement'
class SomeElement extends HTMLElement {
attachedCallback() {
console.log(this.children[0] instanceof OtherElement) // false
setTimeout(() => {
console.log(this.children[0] instanceof OtherElement) // true
}, 0)
}
}
其中OtherElement 是对将在某个时候注册的自定义元素类的引用。请注意,在我的情况下,我使用的是 Chrome v0 document.registerElement。之所以需要超时,是因为如果SomeElement 像下面的代码一样首先注册,那么OtherElement 还不会被注册,因此如果SomeElement 元素的子元素应该是OtherElement 的一个实例,那么在接下来升级这些元素之前,情况将不会如此。
document.registerElement('some-el', SomeElement)
document.registerElement('other-el', OtherElement)
理想情况下,这样的超时是不可取的,因为如果升级恰好需要更长的时间(由于某些可能取决于浏览器实现的未知原因),那么超时黑客也会失败。
我想要一种绝对的方式来等待升级而不会出现故障,并且尽可能不进行轮询。也许它也需要在一段时间后取消?
编辑:理想的解决方案是让我们等待任何第三方自定义元素的升级,而无需在运行前修改这些元素,也无需在运行时进行猴子补丁。
编辑:从观察 Chrome 的 v0 行为来看,似乎第一次调用 document.registerElement('some-el', SomeElement) 会导致这些元素被升级,并且它们的 attachedCallback 方法在OtherElement 注册之前被触发 ,所以孩子不会是正确的类型。然后,通过延迟逻辑,我可以在孩子也升级为OtherElement 类型之后运行逻辑。
编辑:这是一个显示 the problem 的 jsfiddle,这是一个显示 the timeout hack solution 的 jsfiddle。两者都是用 Chrome Canary 中的 Custom Elements v1 API 编写的,在其他浏览器中不起作用,但是使用 Chrome Stable 的 Custom Elements v0 API 和 document.registerElement 和 attachedCallback 而不是 customElements.define 和 @987654344 时问题是一样的@。 (请参阅两个小提琴中的控制台输出。)
【问题讨论】:
-
您可以调度自定义事件或从 connectedCallback 设置 Promise。
-
@Supersharp 如果我等待的元素是我的,那将起作用。但是,如果我们使用第三方元素并且不想派生这些元素本身(假设它们是作为 NPM 的包安装的)。理想情况下,该解决方案允许我们等待任何第三方自定义元素的升级,而无需在运行前修改这些元素,也无需在运行时进行猴子补丁。
-
我不确定你如何在 V0 中做到这一点,但在 V1 中,
customElement对象提供了whenDefined方法,该方法采用tagName,并返回一个 Promise,当定义了带有tagName的 customElement。你可以做window.customElement.whenDefined(e.tagName).then(() => console.log('defined')) -
@arkanciscan 这行得通,只是我不知道我的自定义元素类的最终用户将定义什么标签名称。我鼓励最终用户使用
customElements.define来定义和使用自定义元素。所以,在那种情况下这行不通。 -
@trusktr 请查看我刚刚添加的答案 - 它显示了在定义/未定义/升级元素时如何轻松获得,而无需提前亲自了解这些自定义元素的
localName:)
标签: javascript dom polymer web-component custom-element