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

标签 javascript web-component custom-element native-web-component

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/

相关文章:

Javascript 和 svg,将具有功能的项目添加到页面

vue.js - 无法导入由 vue-cli-service 构建的 Vue 组件

html - 自定义元素 v0 和 v1 之间有什么区别?

web-component - Web 组件嵌套插槽

javascript - 如果父属性评估为真,如何只渲染子组件

javascript - 错误: @angular/platform->browser/platform-browser "' has no exported member ' DOCUMENT'

javascript - 扩展 html 组件获取属性不起作用

javascript - 自定义元素未设置/获取属性

javascript - 指令在引导网格中工作很奇怪

javascript - 从 Shadow DOM 中访问元素