Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/402.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 在自定义元素中迭代HTMLCollection_Javascript_Html_Shadow Dom_Custom Element - Fatal编程技术网

Javascript 在自定义元素中迭代HTMLCollection

Javascript 在自定义元素中迭代HTMLCollection,javascript,html,shadow-dom,custom-element,Javascript,Html,Shadow Dom,Custom Element,如何在另一个自定义元素的影子dom中迭代一个自定义元素的实例?HTMLCollections的行为似乎不符合预期。(说到香草js,我是一个jQuerian和新手,所以我确信我在某处犯了一个明显的错误) HTML 自定义元素定义 对于spk输入: class SpektaularInput扩展了HtmleElement{ 构造函数(){ 超级(); } } window.customElements.define('spk-input',spektaularinput); 对于spk根目录:

如何在另一个自定义元素的影子dom中迭代一个自定义元素的实例?HTMLCollections的行为似乎不符合预期。(说到香草js,我是一个jQuerian和新手,所以我确信我在某处犯了一个明显的错误)

HTML


自定义元素定义

对于
spk输入

class SpektaularInput扩展了HtmleElement{
构造函数(){
超级();
}
}
window.customElements.define('spk-input',spektaularinput);
对于
spk根目录

let template=document.createElement('template');
template.innerHTML=`
`;
类SpektaularRoot扩展了HtmleElement{
构造函数(){
超级();
让shadowRoot=this.attachShadow({mode:'open'});
appendChild(template.content.cloneNode(true));
}
更新(){
让inputs=this.getElementsByTagName('spk-input')
}
connectedCallback(){
这个.update();
}
}
window.customElements.define('spk-root',spektaularroot);

这是我不明白的部分。在
update()
方法中:
console.log(输入)
返回HTMLCollection:

console.log(输入)
//输出
HTMLCollection[]
0:spk输入
1:spk输入
长度:2
__原型:HTMLCollection
但是,HTMLCollection不能使用
for
循环,因为它没有长度

console.log(inputs.length)

// output
0
搜索结果显示HTMLCollections类似于数组,但不是数组。尝试使用
array.from(inputs)
或spread运算符将其设置为数组将导致空数组

这是怎么回事?如何从
update()
方法迭代
spk root
中的
spk input
元素

我用的是大口巴别塔和大口海螺,还有铬。如果需要更多信息,请告诉我。提前谢谢



编辑:为了澄清问题,在
update()中调用
console.log(inputs.length)
而不是
2
,原因是
connectedCallback()在某些情况下,当浏览器遇到自定义元素的开始标记时,将调用自定义元素的
,子元素未被解析,因此不可用。例如,如果您预先定义元素,然后浏览器解析HTML,则会在Chrome中发生这种情况

这就是为什么外部
update()方法中的
let inputs=this.getElementsByTagName('spk-input')
找不到任何元素的原因。不要让自己被误导的console.log输出所愚弄

我最近深入研究了这个主题,并提出了一个使用
HTMLBaseElement
类的解决方案:

Andrea Giammarchi(非支持浏览器中自定义元素的
document register element
polyfill的作者)采纳了该解决方案建议,并从中创建了一个npm包:

只要您不需要动态创建自定义元素,最简单、最可靠的修复方法就是将元素定义脚本放在
正文的末尾,创建升级场景

如果您对该主题的讨论感兴趣(长时间阅读!):

以下是全部要点:

HTMLBaseElement类解决在解析子级之前调用connectedCallback的问题 web组件规范v1存在一个巨大的实际问题:

在某些情况下,当元素的子节点尚不可用时,会调用
connectedCallback

这使得web组件在依赖子组件进行设置的情况下无法正常工作

请参阅以供参考

为了解决这个问题,我们在我们的团队中创建了一个
HTMLBaseElement
类,作为扩展自治自定义元素的新类

HTMLBaseElement
反过来继承自
HTMLElement
(自治自定义元素必须在其原型链中的某个点派生自该元素)

HTMLBaseElement
添加了两件事:

  • 一个
    setup
    方法,负责正确的计时(即确保子节点可访问),然后在组件实例上调用
    childrenAvailableCallback()
  • 一种
    解析的
    布尔属性,默认为
    false
    ,当组件初始设置完成时,该属性将被设置为
    true
    。这意味着作为一种保护,以确保(例如)子事件侦听器不会连接超过一次
HTMLBaseElement 扩展上述功能的组件示例:

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 once
    // to child element nodes using this as a guard
  }
}

HTMLCollection
inputs
确实有一个length属性,如果将其记录在更新函数中,您将看到它的值为2。您还可以在for循环中遍历inputs集合,只要它位于update()函数内

如果要访问更新函数外部的循环中的值,可以将HTMLCollection存储在SpektacularInput类范围外声明的变量中

我想根据您试图完成的任务,还有其他方法来存储这些值,但希望这能回答您最初的问题“如何从update()方法迭代spk root中的spk输入元素?”

class SpektaularInput扩展了HtmleElement{
构造函数(){
超级();
}
}
window.customElements.define('spk-input',spektaularinput);
让template=document.createElement('template');
template.innerHTML=`
`;
//声明外部变量
让inputsObj={};
类SpektaularRoot扩展了HtmleElement{
构造函数(){
超级();
让shadowRoot=this.attachShadow({mode:'open'});
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 once
    // to child element nodes using this as a guard
  }
}