LitElement - 模板中的 ForEach 子项 更新:Mozilla/FireFox 于 2021 年初修复了此错误

问题描述

我想为每个孩子创建 <slot>,例如这里我有一个菜单,我希望每个孩子都被放置在一个 <div>item 类中。
我创建了一个小实用函数来映射孩子:

export function ChildrenMap(el: LitElement,map: (el: HTMLElement,index: number) => TemplateResult): TemplateResult[] {
    console.log(el.children.length) // Returns 0 in Google Chrome and I guess Edge too.
    return (Array.prototype.slice.call(el.children) as HTMLElement[])
                .map(map);
}

然后我在渲染函数中使用它:

render() {
    return html`
        <nav>
        ${ChildrenMap(this,(ele,index) => {
            let id = ele.id ? ele.id :  `item-${index}`;
            ele.setAttribute('slot',id);

            let klass = 'item';
            if(this.selected && this.selected == index) {
                klass += " selected";
            }

            return html`
                <div class="${klass}" data-index="${index}">
                <slot name="${id}"></slot>
                </div>`;
        })}
        </nav>
    `;
}

这在 FireFox 中运行良好,但正如我上面的评论所说,在 Google Chrome 中,元素在渲染点有 0 个子元素,因此 <nav> 为空。
谁能解释为什么元素在渲染时有 0 个子元素? 也许我以错误的方式解决这个问题,有人有其他选择吗?

非常感谢

解决方法

更新:Mozilla/FireFox 于 2021 年初修复了此错误

实际上 FireFox 在这一点上是错误的,它调用了 connectedCallback 为时已晚

Mozilla 工程师 Anne van Kesteren 确认的错误:

有关详细信息,请参阅 StackOverflow 线程:

connectedCallback 中还没有 要读取的 DOM 子项,因为所有 DOM 子项仍在解析中。 (它可能是一个非常大的 DOM 结构)

解决方法(如您所见)是等待:

connectedCallback(){
  setTimeout(()=>{
    // now you can access this. DOM children
  },0);
}

所有带有 Promises 等的建议都有效地执行相同的操作:等待事件循环为空