如何获取自定义元素的内容

问题描述 投票:0回答:2

我正在创建一个 自定义元素,它将能够将其内容从 Markdown 转换为 HTML。但是,我无法获取自定义元素的内容。

<!doctype html>
<html>
<body>
   <template id="mark-down">
      <div class="markdown"></div>
   </template>
   <!-- Converts markdown to HTML -->
   <script src="https://cdn.jsdelivr.net/gh/showdownjs/showdown/dist/showdown.js"></script>
   <script>
      customElements.define('mark-down',
         class extends HTMLElement {
            constructor() {
               super()
               let template = document.querySelector('#mark-down').content
               this.attachShadow({ mode: 'open' }).appendChild(template.cloneNode(true))
            }
            connectedCallback() {
               console.log(this) // Returns the whole <mark-down> node and its contents
               console.log(this.innerHTML) // So why does this return a blank string?
               // This should theoretically work --> let markdown = this.innerHTML
               let markdown = '## Test'
               let converter = new showdown.Converter()
               let html = converter.makeHtml(markdown)
               this.shadowRoot.innerHTML = html;
            }
         });
   </script>

   <main>
      <mark-down>
## Our Markdown

These contents should get converted

* One
* Two
* Three
      </mark-down>
   </main>
</body>
</html>

我的问题在

connectedCallback()
。记录
this
时,我得到整个
<mark-down>
节点及其内容为 markdown。但是,它似乎没有有效的属性。使用
innerHTML
返回一个空白,它应该返回 markdown;其他组合,例如
this.querySelector('mark-down')
,返回
null

如何获取自定义元素的内容?

javascript html web-component
2个回答
9
投票

我写了一篇(非常)长的 Dev.to 博客文章:
Web 组件开发人员还没有连接connectedCallback


最简单的解决方法是

setTimeout
 中的 
connectedCallback

<script>
  customElements.define('my-element', class extends HTMLElement {
    connectedCallback() {
      console.log(this.innerHTML);// "" in all Browsers
      setTimeout(() => {
        // now runs asap 
        console.log(this.innerHTML); // "A"
      });
    }
  })
</script>

<my-element>A</my-element>

这个和所有提到的解决方法的作用是推迟代码执行,直到 DOM 被完全解析。

setTimeout
DOMContentLoaded
之后运行,但是如果您将所有内容包装在
DOMContentLoaded
中,整个元素创建都会延迟,同样适用于
defer
或将
<script>
放在页面末尾

Supersharp 更好地解释了原因:

等待connectedCallback中的Element Upgrade:FireFox和Chromium差异


3
投票

经过一些在线研究,我发现了以下关于connectedCallback

的要点
每次将自定义元素附加到文档连接元素中时。每次移动节点时都会发生这种情况,并且 可能在元素的内容完全解析之前发生

因此,根据浏览器的不同,

innerHTML
在使用时实际上可能没有被定义。这就是为什么上面的代码片段虽然在 Firefox 中运行良好,但在 Chrome 或 Edge 中却不起作用。

要解决这个问题,请将

script
标签放在
body
的底部,在这种情况下,该元素将首先被解析,并且脚本将知道
innerHTML
包含什么。

解决此问题的另一种方法是将自定义元素构造函数包装在 DOM 加载事件中。该事件看起来像这样:

document.addEventListener('DOMContentLoaded', (e) => {
   class markDown extends HTMLElement {
      ...
   }
}

另一种方法是将脚本放入单独的文件中,并使用

script
属性标记
defer
标签。

无论类是否由单独的语句显式命名和定义(如 Triby 的答案所述),还是匿名并由自定义元素定义函数包装(如原始问题中所示),所有三种解决方案都有效。

© www.soinside.com 2019 - 2024. All rights reserved.