gpt4 book ai didi

javascript - 自定义 HTMLElement 的 connectedCallback() 中的 textContent 为空

转载 作者:行者123 更新时间:2023-12-03 16:41:08 35 4
gpt4 key购买 nike

connectedCallback()我的自定义元素的方法 textContent作为空字符串返回。

基本上我的代码归结为以下......

class MyComponent extends HTMLElement{
constructor() {
super()

console.log(this.textContent) // not available here, but understandable
}

connectedCallback() {
super.connectedCallback() // makes no difference if present or not

console.log(this.textContent) // not available here either, but why?!
}
}

customElements.define('my-component', MyComponent);

和HTML...
<my-component>This is the content I need to access</my-component>

从阅读 connectedCallback()听起来一旦将元素添加到 DOM 就会调用它,所以我希望 textContent 属性应该是有效的。

如果有帮助,我正在使用 Chrome 63...

最佳答案

您面临的问题与我们团队在当前项目中遇到的问题基本相同:
connectedCallback in Chrome does not guarantee children are parsed. 具体来说,依赖子元素在 升级 的情况下工作,但如果在浏览器解析元素时预先知道元素,则不起作用。因此,如果您将 webcomponents.js 捆绑包放在 body 的末尾,它至少可以可靠地用于您之前拥有的静态文档(但如果您在 DOMContentLoaded 之后使用 document.write 以编程方式创建元素仍然会失败(您不应该这样做)无论如何))。这基本上就是您发布的解决方案。
更糟糕的是, 没有生命周期钩子(Hook)可以保证自定义元素规范 v1 中的子元素访问。
因此,如果您的自定义元素依赖于子节点进行设置(并且像您的 textContent 这样的简单 textNode 是 子节点),这就是我们经过一周的过度研究和测试后能够提取的内容( which is what the Google AMP team does as well ):

class HTMLBaseElement extends HTMLElement {
constructor(...args) {
const self = super(...args)
self.parsed = false // guard to make it easy to do certain stuff only once
self.parentNodes = []
return self
}

setup() {
// collect the parentNodes
let el = this;
while (el.parentNode) {
el = el.parentNode
this.parentNodes.push(el)
}
// check if the parser has already passed the end tag of the component
// in which case this element, or one of its parents, should have a nextSibling
// if not (no whitespace at all between tags and no nextElementSiblings either)
// resort to DOMContentLoaded or load having triggered
if ([this, ...this.parentNodes].some(el=> el.nextSibling) || document.readyState !== 'loading') {
this.childrenAvailableCallback();
} else {
this.mutationObserver = new MutationObserver(() => {
if ([this, ...this.parentNodes].some(el=> el.nextSibling) || document.readyState !== 'loading') {
this.childrenAvailableCallback()
this.mutationObserver.disconnect()
}
});

this.mutationObserver.observe(this, {childList: true});
}
}
}

class MyComponent extends HTMLBaseElement {
constructor(...args) {
const self = super(...args)
return self
}

connectedCallback() {
// when connectedCallback has fired, call super.setup()
// which will determine when it is safe to call childrenAvailableCallback()
super.setup()
}

childrenAvailableCallback() {
// this is where you do your setup that relies on child access
console.log(this.innerHTML)

// when setup is done, make this information accessible to the element
this.parsed = true
// this is useful e.g. to only ever attach event listeners to child
// elements once using this as a guard
}
}

customElements.define('my-component', MyComponent)
<my-component>textNode here</my-component>

更新 :很久以前 Andrea Giammarchi (@webreflection),自定义元素 polyfill document-register-element(例如,Google AMP 正在使用)的作者,他强烈主张将这样的 parsedCallback 引入自定义元素' API,已采用上述代码并从中创建了一个包 html-parsed-element,这可能会对您有所帮助:

https://github.com/WebReflection/html-parsed-element


您只需从包提供的 HTMLParsedElement 基类(而不是 HTMLElement )派生您的元素。反过来,该基类继承自 HTMLElement

关于javascript - 自定义 HTMLElement 的 connectedCallback() 中的 textContent 为空,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48498581/

35 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com