我正在使用Web Components v1。
假设有两个自定义元素:
父 - element.html
<template id="parent-element">
<child-element></child-element>
</template>
儿童-element.html
<template id="child-element">
<!-- some markup here -->
</template>
我尝试在connectedCallback
中使用parent-element
初始化整个父/子DOM结构,这需要与child-element
中定义的方法进行交互。< / p>
但是,在child-element
connectedCallback
被customElement
解雇时似乎没有正确定义class parent_element extends HTMLElement {
connectedCallback() {
//shadow root created from template in constructor previously
var el = this.shadow_root.querySelector("child-element");
el.my_method();
}
}
:
父 - element.js
el
这不起作用,因为HTMLElement
是预期的child-element
而不是parent-element
。
一旦其模板中的所有子自定义元素都已正确附加,我就需要this.parentElement
的回调。
this question中的解决方案似乎不起作用; null
child-element
connectedCallback()
内的@return map-get($props, color);
。
ilmiont
答案 0 :(得分:3)
connectedCallback
存在时间问题。在升级任何自定义元素子元素之前,它首次被调用。 <{1}}只是在调用<child-element>
时的HTMLElement。
要获得升级的子元素,您需要在超时时间内执行此操作。
运行以下代码并观察控制台输出。当我们尝试调用孩子的方法时,它会失败。同样,这是因为Web组件的创建方式。以及调用connectedCallback
的时间。
但是,在connectedCallback
内,对孩子方法的调用有效。这是因为您允许将child元素的时间升级到自定义元素。
如果你问我,有点傻。我希望在所有孩子升级之后还有另一个函数被调用。但我们与我们的工作合作。
setTimeout
class ParentElement extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: 'open'});
this.shadowRoot.innerHTML = '<h2>Parent Element</h2><child-element></child-element>';
}
connectedCallback() {
let el = this.shadowRoot.querySelector("child-element");
console.log('connectedCallback', el);
try {
el.childMethod();
}
catch(ex) {
console.error('Child element not there yet.', ex.message);
}
setTimeout(() => {
let el = this.shadowRoot.querySelector("child-element");
console.log('setTimeout', el);
el.childMethod();
});
}
}
customElements.define('parent-element', ParentElement);
class ChildElement extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: 'open'});
this.shadowRoot.innerHTML = '<h3>Child Element</h3>';
}
childMethod() {
console.info('In Child method');
}
}
customElements.define('child-element', ChildElement);
答案 1 :(得分:3)
在ShadowDOM模板中使用广告位元素。
将 custom-elements 添加到ShadowDOM模板是一种不好的做法。每个自定义元素都必须能够不受DOM中其他自定义元素的依赖。在ShadowDOM中使用本机HTML元素没有问题,因为它们将始终有效。
为此,引入了slot element。使用slot元素,您可以在ShadowDOM模板中创建占位符。只需将元素放在DOM中的 custom-element 中即可使用这些占位符。
但是您怎么知道占位符是否已填充元素?
插槽元素可以监听称为slotchange
的唯一事件。只要将一个(或多个)元素放置在slot
元素的位置,就会触发该事件。
在事件的侦听器内部,您可以使用HTMLSlotElement.assignedNodes()
或HTMLSlotElement.assignedElements()
方法访问占位符中的所有元素。它们返回一个数组,其中元素放置在slot
中。
class ParentElement extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: 'open'});
this.shadowRoot.innerHTML = '<h2>Parent Element</h2><slot></slot>';
console.log("I'm a parent. I have slots.");
// Select the slot element and listen for the slotchange event.
const slot = this.shadowRoot.querySelector('slot');
slot.addEventListener('slotchange', (event) => {
const children = event.target.assignedElements();
children.forEach(child => child.shout());
});
}
}
customElements.define('parent-element', ParentElement);
class ChildElement extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: 'open'});
this.shadowRoot.innerHTML = '<h3>Child Element</h3>';
}
shout() {
console.log("I'm a child, placed inside a slot.");
}
}
customElements.define('child-element', ChildElement);
<parent-element>
<child-element></child-element>
<child-element></child-element>
<child-element></child-element>
</parent-element>
答案 2 :(得分:2)
经过一些工作,我有各种各样的解决方案。
当然this.parentElement
在子元素中不起作用;它是影子DOM的根源!
我目前的解决方案,对我的具体情况来说没问题,如下:
<强>父 - element.js 强>
init() {
//Code to run on initialisation goes here
this.shadow_root.querySelector("child-element").my_method();
}
儿童-element.js 强>
connectedCallback() {
this.getRootNode().host.init();
}
因此,在子元素中,我们得到根节点(模板阴影DOM),然后是它的主机,父元素,并调用init(...)
,此时父节点可以访问子节点并且它是完全定义的。 / p>
由于几个原因,这个解决方案并不理想,所以我并没有将其标记为已被接受。
1)如果有多个孩子要等待或者更深层次的嵌套,那么编排回调会变得更加复杂。
2)我担心child-element
的含义,如果我想在独立容量中使用这个元素(即在其他地方,完全独立于嵌套在parent-element
中)我将拥有修改它以明确检查getRootNode().host
是parent-element
的实例。
所以这个解决方案现在可以工作,但感觉很糟糕,我认为当它的整个DOM结构(包括其阴影DOM中的嵌套自定义元素)被初始化时,需要有一个对父进行激活的回调。
答案 3 :(得分:1)
如果要避免由于setTimeout的延迟而引起的任何视觉故障,可以使用MutationObserver。
class myWebComponent extends HTMLElement
{
connectedCallback() {
var instance = this;
var childrenConnectedCallback = () => {
var addedNode = instance.childNodes[(instance.childNodes.length - 1)];
/* callback here */
}
var observer = new MutationObserver(childrenConnectedCallback);
var config = { attributes: false, childList: true, subtree: true };
observer.observe(instance, config);
//make sure to disconnect
setTimeout(() => {
observer.disconnect();
}, 0);
}
}
答案 4 :(得分:0)
我们遇到了非常相关的问题,自定义元素(v1)的connectedCallback
中没有孩子。
首先,我们尝试使用一种非常复杂的方法来修复connectedCallback
,Google AMP团队也正在使用该方法(mutationObserver
并检查nextSibling
的组合)最终导致到https://github.com/WebReflection/html-parsed-element
不幸的是,这本身就产生了问题,因此我们回到始终强制执行升级的情况(即,包括仅在页面末尾注册自定义元素的脚本)。
答案 5 :(得分:-2)
document.addEventListener('DOMContentLoaded', defineMyCustomElements);
u可以延迟定义ur类,直到加载dom之后。