Это из-за процесса обновления пользовательского элемента .
1-й шаг : при выполнении document.body.innerHTML = '<custom-parent><custom-child>foo</custom-child></custom-parent>'
2 элемента вставляется на страницу как неизвестные элементы .
2-й шаг : родительский элемент обновлен первым. Он может получить доступ к своему дочернему элементу (а затем обновить свое свойство textContent
) как элемент unknown . Но он не может получить доступ к методу пользовательского элемента test()
... потому что это еще не пользовательский элемент!
3-й шаг : дочерний элемент обновлен сразу после, и теперь получает метод test()
.
4-й шаг : отложенный вызов test()
логически работает :-)
Смотрите пример ниже. Он использует querySelectorAll( ':not(:defined)' )
, чтобы показать, что ребенок обновлен после своего родителя.
class CustomParent extends HTMLElement {
constructor() { super() ; console.log( 'parent upgraded') }
connectedCallback() {
console.log( 'parent connected', this.children[0].outerHTML )
// works
this.children[0].textContent = 'bar'
// works
setTimeout( () => this.children[0].test() )
// throws a Type error
try {
this.children[0].test()
} catch ( e ) {
//this shows the parent is upgraded, but not its child
var not_upgraded = document.querySelectorAll( ':not(:defined)' )
console.log( 'not upgraded: ', ...not_upgraded )
}
}
}
customElements.define( 'custom-parent', CustomParent )
class CustomChild extends HTMLElement {
constructor() { super() ; console.log( 'child upgraded') }
test() { this.textContent = 'baz' }
}
customElements.define( 'custom-child', CustomChild )
document.body.innerHTML = `
<custom-parent>
<custom-child>foo</custom-child>
</custom-parent>`