当其中一个子节点具有 name="children" 时,不能使用 Element.children

Can't use Element.children when one of the child nodes has name="children"

我在使用 Element.children 时注意到一个奇怪的问题,似乎没有找到好的解决方法。

示例 1(预期行为)

拿这个HTML:

<form>
  <input name="hi">
  <input name="bye">
</form>

还有这个 JS

const formElement = document.querySelector('form');
for (let i = 0; i < formElement.children.length; i++) {
  console.log(formElement.children[i].name);
}

控制台打印出如下内容,如您所料:

"hi"
"bye"

示例 2(奇怪的行为)

现在,让我们添加一个带有 name="children"

的输入字段
<form>
  <input name="hi">
  <input name="bye">
  <input name="children">
</form>

控制台不打印任何内容。

我认为为什么会这样

formElement.children return 一个 HTML 集合。 在 HTML 集合中,您可以通过索引访问子元素,或直接通过您尝试定位的元素的名称属性访问。

因此,为了获得 "hi" 元素,您可以说 formElement.children[0]formElement.hi.

但是当集合中有名称为"children"的元素时,formElement.children将return名称为“children”的元素,并且不再有任何办法遍历所有元素。

我该如何解决这个问题?

这是我的问题。我知道我不能简单地不使用“children”这个名字而选择其他名字,但肯定有一种方法可以使它起作用?

这里提笔说明问题:https://codepen.io/pwkip/pen/XWVoXVE


编辑:

这似乎与 formElement 是一个 <form> 这一事实有关。当我将其更改为 <div> 时,一切正常。所以我想问题归结为: 如何将 HTMLFormElement 转换为常规 HTMLElement?

这是因为非常不幸的历史原因,HTMLFormElement 有一个 named property getter, which will return<input> 元素,它们有 .name.id 属性 值设置为给定名称。 实际上它比那更复杂,但没那么有趣。

以我的愚见,这确实是规范中的一个怪癖,但如果不破坏旧网站就无法删除它,这是规范作者不太喜欢的。

所以是的,这个 named getter 将优先于原型链中继承的任何其他 getter。

如果您真的不想更改元素的 name,您可以在 HTMLFormElement 上显式调用 Element.children getter,或者更简单的方法可能只是使用 .querySelectorAll("*") (假设您没有具有此类名称或 ID 的元素;-)

const form = document.querySelector("form");

console.log("with .children:", form.children); // our <input>

const getter = Object.getOwnPropertyDescriptor(Element.prototype, "children").get;
console.log("with Element's getter:", getter.call(form)); // an HTMLCollection

console.log("with querySelectorAll:", form.querySelectorAll("*")); // a NodeList
<form>
  <input name="foo">
  <input name="children">
</form>