Jon*_*son 2 javascript web-component web 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);
Run Code Online (Sandbox Code Playgroud)
还有HTML ...
<my-component>This is the content I need to access</my-component>
Run Code Online (Sandbox Code Playgroud)
从阅读方面看,connectedCallback()这听起来好像是在将元素添加到DOM后就被调用了,所以我希望textContent属性应该是有效的。
我正在使用Chrome 63,如果有帮助...
您面临的问题与我们的团队在当前项目中遇到的问题基本相同:
connectedCallback在Chrome浏览器中不能保证对子对象进行解析。具体来说,在升级情况下,依赖子项是有效的,但是如果在浏览器解析该元素时预先知道该元素,则将无法使用子项。因此,如果将webcomponents.js包放在的末尾body,它至少可以可靠地用于您之前拥有的静态文档(但是如果您在DOMContentLoaded使用document.write之后以编程方式创建元素,仍然会失败(无论如何您都不应这样做) )。这基本上就是您发布的解决方案。
更糟的是,“自定义元素”规范v1中没有生命周期挂钩可以确保对子元素的访问。
因此,如果您的自定义元素依赖于子级来设置(而像您这样的简单textNode textContent 就是子级节点),那么这就是我们经过一周的大量研究和测试后能够提取的内容(Google AMP小组也这样做了)):
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)Run Code Online (Sandbox Code Playgroud)
<my-component>textNode here</my-component>Run Code Online (Sandbox Code Playgroud)
更新:很早以前,自定义元素polyfill document-register-element(例如,Google AMP正在使用)的作者Andrea Giammarchi(@webreflection)大力倡导将这样的a引入parsedCallback自定义元素的API中上面的代码,并html-parsed-element从中创建一个包,可能会帮助您:
您只需从HTMLParsedElement包提供的基类(而不是HTMLElement)派生您的元素。该基类又继承自HTMLElement。
您可以使用插槽和 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);
})();Run Code Online (Sandbox Code Playgroud)
<my-component>This is the content I need to access</my-component>Run Code Online (Sandbox Code Playgroud)
我设法通过仅customElements.define('my-component', MyComponent);在 DOMContentLoaded 事件触发后调用来解决此问题。
document.addEventListener('DOMContentLoaded', function() {
customElements.define('my-component', MyComponent);
}
Run Code Online (Sandbox Code Playgroud)
这种行为看起来有点奇怪,因为您期望connectedCallback只有在节点插入 DOM 并完全准备好进行操作时才会触发。
| 归档时间: |
|
| 查看次数: |
544 次 |
| 最近记录: |