tru*_*ktr 4 javascript dom web-component polymer custom-element
我有一个元素的引用,该元素有时会升级为自定义元素。我如何等待它升级?
例如,假设el是参考。如果假设为此目的附加了承诺,则代码可能类似于
await el.upgradePromise
// do something after it has been upgraded.
Run Code Online (Sandbox Code Playgroud)
那当然不存在,但是描述了我想做什么。也许没有轮询就没有办法吗?如果使用轮询,我将轮询什么(假设我没有对应该升级到的类构造函数的引用)。也许我可以轮询el.constructor并等待其不属于HTMLElement,或等待它不被HTMLUnknownElement?
编辑:对于背景,我有一些类似以下的代码,其中使用setTimeout是为了使代码正常工作的技巧。第一个console.log输出false,而超时中的一个输出true。
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)
}
}
Run Code Online (Sandbox Code Playgroud)
在哪里OtherElement引用将在某个时候注册的Custom Element类。请注意,我使用的是Chrome v0 document.registerElement。需要超时,因为如果SomeElement首先按以下代码OtherElement注册,则将尚未注册,因此,因此如果SomeElement元素的子级是的实例OtherElement,那么在升级这些元素之前不会如此下一个。
document.registerElement('some-el', SomeElement)
document.registerElement('other-el', OtherElement)
Run Code Online (Sandbox Code Playgroud)
理想情况下,这样的超时是不希望的,因为如果升级花费了更长的时间(由于某些未知原因,可能取决于浏览器的实现),那么超时破解也将失败。
我想要一种绝对的方式来等待升级,而不会出现故障,并且如果可能的话也不会进行轮询。也许过一段时间也需要取消吗?
编辑:理想的解决方案将使我们能够等待任何第三方自定义元素的升级,而无需在运行前修改这些元素,也不必在运行时进行猴子补丁。
编辑:从观察Chrome的v0行为来看,似乎第一个调用document.registerElement('some-el', SomeElement)导致那些元素升级,并且在注册之前attachedCallback会激发它们的方法,因此子元素将不是正确的类型。然后,通过延迟逻辑,我可以在子级也升级为type后运行逻辑。OtherElementOtherElement
编辑:这是一个显示问题的jsfiddle,这是一个显示超时hack解决方案的jsfiddle 。两者都是使用Chrome Canary中的Custom Elements v1 API编写的,在其他浏览器中均无法使用,但是使用Chrome Stable的Custom Elements v0 API和document.registerElement和attachedCallback而不是customElements.define和时出现的问题相同connectedCallback。(请参阅两个小提琴中的控制台输出。)
小智 5
您可以使用window.customElements.whenDefined("my-element")which返回a Promise,可以用来确定何时升级元素。
window.customElements.whenDefined('my-element').then(() => {
// do something after element is upgraded
})Run Code Online (Sandbox Code Playgroud)
由于synchtml 和 javascript 解析的顺序,您只需等待元素被定义和插入。
第一个测试用例 - 插入 HTML,然后定义元素:
<el-one id="E1">
<el-two id="E2">
</el-two>
</el-one>
<script>
// TEST CASE 1: Register elements AFTER instances are already in DOM but not upgraded:
customElements.define('el-one', ElementOne)
customElements.define('el-two', ElementTwo)
// END TEST CASE 1
console.assert( E1 instanceof ElementOne )
console.assert( E2 instanceof ElementTwo )
</script>
Run Code Online (Sandbox Code Playgroud)
第二个测试用例 - 定义然后插入的元素:
// TEST CASE 2: register elements THEN add new insances to DOM:
customElements.define('el-three', ElementThree)
customElements.define('el-four', ElementFour)
var four = document.createElement('el-four')
var three = document.createElement('el-three')
three.appendChild(four)
document.body.appendChild(three)
// END TEST CASE 2
console.assert( three instanceof ElementThree )
console.assert( four instanceof ElementFour )
Run Code Online (Sandbox Code Playgroud)
<el-one id="E1">
<el-two id="E2">
</el-two>
</el-one>
<script>
// TEST CASE 1: Register elements AFTER instances are already in DOM but not upgraded:
customElements.define('el-one', ElementOne)
customElements.define('el-two', ElementTwo)
// END TEST CASE 1
console.assert( E1 instanceof ElementOne )
console.assert( E2 instanceof ElementTwo )
</script>
Run Code Online (Sandbox Code Playgroud)
// TEST CASE 2: register elements THEN add new insances to DOM:
customElements.define('el-three', ElementThree)
customElements.define('el-four', ElementFour)
var four = document.createElement('el-four')
var three = document.createElement('el-three')
three.appendChild(four)
document.body.appendChild(three)
// END TEST CASE 2
console.assert( three instanceof ElementThree )
console.assert( four instanceof ElementFour )
Run Code Online (Sandbox Code Playgroud)
第三个测试用例 - 未知元素名称
如果您不知道内部元素的名称是什么,您可以解析外部元素的内容并whenDefined()在每个发现的自定义元素上使用。
class ElementZero extends HTMLElement {
connectedCallback() {
console.log( '%s connected', this.localName )
}
}
class ElementOne extends ElementZero { }
class ElementTwo extends ElementZero { }
// TEST CASE 1: Register elements AFTER instances are already in DOM but not upgraded:
customElements.define('el-one', ElementOne)
customElements.define('el-two', ElementTwo)
// END TEST CASE 1
console.info( 'E1 and E2 upgraded:', E1 instanceof ElementOne && E2 instanceof ElementTwo )
class ElementThree extends ElementZero { }
class ElementFour extends ElementZero { }
// TEST CASE 2: register elements THEN add new insances to DOM:
customElements.define('el-three', ElementThree)
customElements.define('el-four', ElementFour)
const E4 = document.createElement('el-four')
const E3 = document.createElement('el-three')
E3.appendChild(E4)
document.body.appendChild(E3)
// END TEST CASE 2
console.info( 'E3 and E4 upgraded:', E3 instanceof ElementThree && E4 instanceof ElementFour )Run Code Online (Sandbox Code Playgroud)
<el-one id="E1">
<el-two id="E2">
</el-two>
</el-one>Run Code Online (Sandbox Code Playgroud)
注意如果您必须等待不同的自定义元素升级,您将寻求解决Promise.all()方案。您可能还想执行更详细的(递归)解析。
| 归档时间: |
|
| 查看次数: |
1094 次 |
| 最近记录: |