在我的自定义元素的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
答案 0 :(得分:2)
您面临的问题与我们的团队在当前项目中遇到的问题基本相同:
connectedCallback
in Chrome does not guarantee children are parsed.具体来说,在 upgrade 情况下,依赖子项是有效的,但是如果在浏览器解析该元素时预先知道该元素,则不起作用。因此,如果将webcomponents.js
包放置在body
的末尾,它至少可以可靠地用于您之前拥有的静态文档(但是如果您在{{ 1}})。这基本上就是您发布的解决方案。
更糟糕的是,在“自定义元素”规范v1中没有生命周期挂钩可以保证子元素的访问。
因此,如果您的自定义元素依赖于子级来设置(而像DOMContentLoaded
这样的简单textNode就是子级节点),那么我们就是经过一周的过度研究和测试(which is what the Google AMP team does as well)后可以提取:
textContent
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)
答案 1 :(得分:1)
我设法通过在DOMContentLoaded事件被触发后仅调用customElements.define('my-component', MyComponent);
来解决这个问题。
document.addEventListener('DOMContentLoaded', function() {
customElements.define('my-component', MyComponent);
}
这种行为似乎有点奇怪,因为你期望connectedCallback
只有在节点插入DOM并且完全准备好被操作后才会触发。
答案 2 :(得分:1)
您可以使用插槽和slotchange事件(插槽获取主机标签内容)来访问内容。
(function(){
class MyComponent extends HTMLElement {
constructor() {
super();
let slot = document.createElement('slot') ;
slot.addEventListener('slotchange', function(e) {
let nodes = slot.assignedNodes();
console.log('host text: ',nodes[0].nodeValue);
});
const shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.appendChild(slot);
}
}
window.customElements.define('my-component', MyComponent);
})();
<my-component>This is the content I need to access</my-component>