用文本节点替换`<span>`:这是程序员错误还是浏览器错误?

U. *_*ndl 2 javascript collections dom replace

我正在尝试替换 HTML 中一些看起来像 的占位符<span id="Something" />。使用以下 JavaScript 代码仅替换了第一次出现的情况,我想知道为什么:

function set_placeholder(cls, txt)
{
    txt = document.createTextNode(txt);
    for (var e of document.getElementsByClassName(cls)) {
        e.parentNode.replaceChild(txt, e);
    }
}
Run Code Online (Sandbox Code Playgroud)

span替换后,集合似乎无法找到下一个匹配项。

所以我尝试使用以下变体插入文本:

function set_placeholder(cls, txt)
{
    for (var e of document.getElementsByClassName(cls)) {
        e.innerText = txt;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在所有的出现都被替换了,让我想知道这是我的错,还是浏览器(Firefox 102)的错,当第一个变体失败时。

HTML 示例

实际的 HTML 要复杂得多,但这里有一些示例:

<html>
 <p><span class="ph-customer" /> bestellte am <span class="ph-customer-date" /> folgende Artikel:</p>
<!-- ... -->
 <table>
  <tr>
    <td><span class="ph-customer-date" />,
    <span class="ph-customer-name" /></td>
  </tr>
 </table>
<!-- ... -->
</html>
Run Code Online (Sandbox Code Playgroud)

例如,ph-customer-date发生两次,但调用set_placeholder('ph-customer-date', '30.12.2023')只会替换第一次出现。

ibr*_*cin 7

实施是正确的,并且20年来一直如此。您所观察到的是,您正在处理一场直播HTMLCollectionfor并将使用HTMLCollection.prototype[Symbol.iterator]来获取成员。正如其他人正确指出的那样,replaceChild将弹出第 0 个项目,第 1 个将是第 0 个,第 2 个将是第一个。相反,将其转换为静态的东西:

Array.from(...)

您的第二个示例之所以有效,是因为它修改了对象引用(在本例中为节点)的内容,并且没有从;span中删除指向该对象的指针。HTMLCollection这样的“安全”方法是innerHTML,,textContentinnerText您也会遇到同样的问题outerHTML,它实际上会删除指针。

记住在HTMLCollections直播中,您还需要注意是否NodeList会在直播或非直播中表现出类似的行为。Node.childNodes返回一个活动的,但其他所有带有document.querySelector和的东西都document.querySelectorAll将返回静态NodeList

通常通过以下方式将它们转换为常规数组是安全的Array.from

或使用document.querySelectorAll(".whateverclass")

Array.from(document.getElementsByTagName("DIV")).forEach((div, i) => {
  if(!i){
    //method1 - DOES NOT WORK
    for (const span of div.getElementsByClassName("a")) {
      div.replaceChild(document.createTextNode("!"), span)
    }
  } else {
    //method2 - WORKS
    for (const span of Array.from(div.getElementsByClassName("b"))) {
      div.replaceChild(document.createTextNode("!"), span)
    }
  }
})
Run Code Online (Sandbox Code Playgroud)
<div>
  <span class="a">x</span>
  <span class="a">y</span>
  <span class="a">z</span>
</div>

<div>
  <span class="b">u</span>
  <span class="b">v</span>
  <span class="b">w</span>
</div>
Run Code Online (Sandbox Code Playgroud)