【问题标题】:insertBefore on multiple elements only work with the last oneinsertBefore 在多个元素上仅适用于最后一个
【发布时间】:2018-11-25 16:36:06
【问题描述】:

我有一个包含大量输入元素的表单,但没有告诉用户哪些字段是必需的。问题是我无法访问它的 HTML 代码。

所以我正在编写这个 JavaScript:

var allInputs = document.querySelectorAll("input");  
var newItem = document.createElement("LI");  
var textnode = document.createTextNode("(*)");  
newItem.appendChild(textnode);  
for (var i = 0; i < allInputs.length; i++) {  
        if(allInputs[i].hasAttribute('required') == true){  
          allInputs[i].parentNode.insertBefore(newItem, allInputs[i]);  
        }  
}  

结果:它仅在最后一个输入之前添加 (*)。我尝试在浏览器控制台上逐行运行此代码,我注意到它在输入中添加了文本并删除了前一个。

我不是网络开发人员,我使用的是在互联网上找到的示例,所以这对我来说很棘手:/

【问题讨论】:

    标签: javascript required appendchild textnode


    【解决方案1】:

    在循环开始之前,您只创建了一次新的 li,因此每次您 insertBefore 时,您都会从之前的位置删除 li 并将其放入新位置。

    如果新元素只有一个子节点,并且该子节点是一个文本节点,那么简单地分配给textContent 就不会那么冗长了。

    改为在每次迭代时创建一个新的li

    const allInputs = document.querySelectorAll("input");
    for (let i = 0; i < allInputs.length; i++) {  
      if(allInputs[i].hasAttribute('required') == true){  
        const newItem = document.createElement("LI");  
        newItem.textContent = '(*)';
        allInputs[i].parentNode.insertBefore(newItem, allInputs[i]);
      }  
    }  
    

    【讨论】:

      【解决方案2】:

      您实际上是在每个输入旁边添加元素。但是由于您引用的是相同的newItem,它只是将元素从一个位置移动到下一个位置,而不是在该位置创建一个新元素。

      使用cloneNode() 为您的元素制作一个新副本,您可以将其放置在每个位置。

      allInputs[i].parentNode.insertBefore(newItem.cloneNode(true), allInputs[i]);  
      

      【讨论】:

        【解决方案3】:
        function addAsterisk(node){ 
            var newItem = document.createElement("LI");  
            var textnode = document.createTextNode("(*)");  
            newItem.appendChild(textnode);
            node.parentNode.insertBefore(newItem, node);
        }
        
        var allInputs = document.querySelectorAll("input"); 
        
        for (var i = 0; i < allInputs.length; i++) {  
                if(allInputs[i].hasAttribute('required') == true){
                  addAsterisk(allInputs[i]);
                }  
        } 
        

        【讨论】:

          【解决方案4】:

          我不知道您想在哪里放置标记,但将其添加到 &lt;li&gt; 会使标记出现在新行上。

          我个人会在输入的一侧添加标记,如下所示:

          const allInputs = document.querySelectorAll("input[required]");
          const addMark = x => x.parentNode.appendChild(document.createTextNode("*"));
          [...allInputs].forEach(addMark);
          <ul>
          <li><label>First name <input required/></label>
          <li><label>Second name <input/></label>
          <li><label>Email<input type="email" required/></label>
          <li><label>Information <input/></label>
          </ul>

          【讨论】: