如何获取自定义元素的内容
How to Get the Contents of a Custom Element
我正在创建一个 custom element,它将能够将其内容从 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
returns 一个空白,它应该 return 降价;其他组合,例如 this.querySelector('mark-down')
、return null
.
如何获取自定义元素的内容?
在网上进行一些研究后,我发现 following nugget 关于 connectedCallback
:每次将自定义元素附加到文档连接元素中。每次移动节点时都会发生这种情况,并且可能会在元素的内容被完全解析之前发生。
因此,根据浏览器的不同,innerHTML
在使用时可能实际上没有定义。这就是为什么上面的代码片段虽然在 Firefox 中很好,但在 Chrome 或 Edge 中不起作用。
为了解决这个问题,将script
标签放在body
的底部,这样元素会先被解析,脚本会知道innerHTML
包含。
另一种解决方法是将自定义元素构造函数包装在 DOM 加载事件中。该事件看起来像这样:
document.addEventListener('DOMContentLoaded', (e) => {
class markDown extends HTMLElement {
...
}
}
另一种方法是将您的脚本放在一个单独的文件中,并使用 defer
属性标记 script
标签。
无论 class 是否由单独的语句显式命名和定义(如 Triby 的回答所述),或匿名并由自定义元素定义函数包装(如原始问题中所述),所有三种解决方案均有效.
被这个咬了那么多,特意问了个Whosebug的问题让人找
最简单的解决方法是 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 更好地解释了原因:
我正在创建一个 custom element,它将能够将其内容从 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
returns 一个空白,它应该 return 降价;其他组合,例如 this.querySelector('mark-down')
、return null
.
如何获取自定义元素的内容?
在网上进行一些研究后,我发现 following nugget 关于 connectedCallback
:每次将自定义元素附加到文档连接元素中。每次移动节点时都会发生这种情况,并且可能会在元素的内容被完全解析之前发生。
因此,根据浏览器的不同,innerHTML
在使用时可能实际上没有定义。这就是为什么上面的代码片段虽然在 Firefox 中很好,但在 Chrome 或 Edge 中不起作用。
为了解决这个问题,将script
标签放在body
的底部,这样元素会先被解析,脚本会知道innerHTML
包含。
另一种解决方法是将自定义元素构造函数包装在 DOM 加载事件中。该事件看起来像这样:
document.addEventListener('DOMContentLoaded', (e) => {
class markDown extends HTMLElement {
...
}
}
另一种方法是将您的脚本放在一个单独的文件中,并使用 defer
属性标记 script
标签。
无论 class 是否由单独的语句显式命名和定义(如 Triby 的回答所述),或匿名并由自定义元素定义函数包装(如原始问题中所述),所有三种解决方案均有效.
被这个咬了那么多,特意问了个Whosebug的问题让人找
最简单的解决方法是 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 更好地解释了原因: