使用JavaScript删除特定的<li>元素

9
该函数似乎不能删除包含指定值的节点,除非它是第一个值(在这种情况下是“apples”)。同时需要循环两次才能执行任何删除。为什么会这样呢?
function removeSpec()
{
    var query = document.getElementById('spec').value;  /* Value inputted by user */
    elements = document.getElementsByClassName('fruit'); /* Get the li elements in the list */
    var myList = document.getElementById("myList3"); /* Var to reference the list */
    var length = (document.getElementsByClassName('fruit').length); /* # of li elements */
    var checker = 'false'; /* boolean-ish value to determine if value was found */

    for(var counter = 0; counter < length; counter ++)
    {
        if (elements[counter].textContent == query )
        {
             alert("Counter : " + counter);
             myList.removeChild(myList.childNodes[ (counter) ]);
             checker="true";
        }
    }
  if ( checker == "false") 
   {
       alert("Not Found");
   }
}

相应的HTML代码如下:
  <ul id="myList3">
                <li class="fruit" >Apples</li>
                <li class="fruit" >Oranges</li>
                <li class="fruit" >Banannas</li>
                <li class="fruit">Strawberry</li>
   </ul>
   <form> 
           Value: <input type="text" name="" value="" id="spec">
   <br><br>
    </form>
    <button type="button" style="height:20px;width:200px" href="javascript:void(0)" onclick="removeSpec()" > 

        Remove Specified 
   </button>
6个回答

13
childNodes 返回所有子节点的列表,包括文本节点。 在每个 <li> 元素之间,都有包含空格和换行符的文本节点。 因此,childNodes 返回包含 9 个节点的列表,但您假定只有包含 4 个节点的列表 (document.getElementsByClassName('fruit').length)。
相比于 .childNodes,您可以使用 .children.children 返回仅包含元素节点的列表。或者更好地使用 elements,因为您正在迭代它们。
您还需要在找到并删除节点后停止迭代,否则您将尝试访问不再存在的位置。

function removeSpec()
{
    var query = document.getElementById('spec').value;  /* Value inputted by user */
    elements = document.getElementsByClassName('fruit'); /* Get the li elements in the list */
    var myList = document.getElementById("myList3"); /* Var to reference the list */
    var length = (document.getElementsByClassName('fruit').length); /* # of li elements */
    var checker = 'false'; /* boolean-ish value to determine if value was found */

    for(var counter = 0; counter < length; counter ++)
    {
        if (elements[counter].textContent == query )
        {
             myList.removeChild(myList.children[ (counter) ]);
             // better: myList.removeChild(elements[counter]);
             checker="true";
             break;
        }
    }
  if ( checker == "false") 
   {
       alert("Not Found");
   }
}
<ul id="myList3">
                <li class="fruit" >Apples</li>
                <li class="fruit" >Oranges</li>
                <li class="fruit" >Banannas</li>
                <li class="fruit">Strawberry</li>
   </ul>
   <form> 
           Value: <input type="text" name="" value="" id="spec">
   <br><br>
    </form>
    <button type="button" style="height:20px;width:200px" href="javascript:void(0)" onclick="removeSpec()" > 

        Remove Specified 
   </button>

还有其他可以改进的地方(例如,为什么不将一个实际的布尔值分配给checker?),但它们与你的问题无关。

还有其他一些可以改进的地方(例如,为什么不将一个真正的布尔值分配给checker?),但这些与你的问题无关。


1
你的回答对其他人更有用...等等,算了 :) - Pierre Arlaud

1

你可以考虑使用下面的方式来替代 for 循环。

查看以下代码片段。

function removeSpec() {
  var query = document.getElementById('spec').value; /* Value inputted by user */
  var elements = document.getElementsByClassName('fruit'); /* Get the li elements in the list */
  var myList = document.getElementById("myList3"); /* Var to reference the list */
  var length = (document.getElementsByClassName('fruit').length); /* # of li elements */
  var checker = 'false'; /* boolean-ish value to determine if value was found */

  myList.querySelectorAll('li').forEach(function(item) {
    if (item.innerHTML == query)
      item.remove();
  });
}
<ul id="myList3">
  <li class="fruit">Apples</li>
  <li class="fruit">Oranges</li>
  <li class="fruit">Banannas</li>
  <li class="fruit">Strawberry</li>
</ul>
<form>
  Value:
  <input type="text" name="" value="" id="spec">
  <br>
  <br>
</form>
<button type="button" style="height:20px;width:200px" href="javascript:void(0)" onclick="removeSpec()">

  Remove Specified
</button>

希望它有所帮助。

1

我运行了这段代码。你应该添加这一行。

elements[counter].remove();

代替这一行
myList.removeChild(myList.childNodes[ (counter) ]);

1
如果您解释一下原因,那么您的答案将对其他人更有用。 - Felix Kling

1
这可能听起来有些疯狂,但是Chrome会将您的HTML无序列表解析为以下内容:
NodeList[9]
0: text
1: li.fruit
2: text
3: li.fruit
4: text
5: li.fruit
6: text
7: li.fruit
8: text
length: 9
__proto__: NodeList

基本上,它似乎为您无序列表中的每个换行符创建一个文本节点。这也解释了为什么仅在第二次调用函数后才进行删除 - 它首先删除文本节点,然后在第二次尝试时删除实际元素。
将您的HTML简单转换为以下形式可以解决问题(但不太美观):
<ul id="myList3"><li class="fruit">Apples</li><li class="fruit">Oranges</li><li class="fruit">Banannas</li><li class="fruit">Strawberry</li></ul>

有一些解决方法可以尝试使用。例如,您可以尝试使用childNode.remove()方法,但并非所有浏览器都支持此方法。

或者,类似以下的方法也可能有效:

selectedChildNode.parentNode.removeChild(selectedChildNode);

5
每个 HTML 解析器都应该以这种方式解析它。这是 HTML/DOM 工作的方式。 - Felix Kling

0

myList是一个li元素的数组,因此在myList上使用removeChild在逻辑上是不正确的。

此外,在这里使用myList.childNodes没有意义。

尝试使用

myList[counter].parentNode.removeChild(myList[counter]);

3
如果您解释一下原因,您的回答对其他人会更有用。 - Felix Kling

0

问题在这里:myList.removeChild(myList.childNodes[ (counter) ]);,因为myList.childNodes返回了8个值而不是4个。我们有包含4个节点的元素数组,因此从元素数组中删除会产生正确的结果。

请尝试下面的代码片段:

function removeSpec() {
        var query = document.getElementById('spec').value;
        elements = document.getElementsByClassName('fruit');

        var myList = document.getElementById("myList3"); 
        var length = elements.length; 
        var checker = 'false'; 

        for(var counter = 0; counter < length; counter ++)
        {           
            if (elements[counter].textContent == query )
            {
                 alert("Counter : " + counter);
                 myList.removeChild(elements[counter]);
                 checker="true";
            }
        }
      if ( checker == "false") 
       {
           alert("Not Found");
       }
}

2
如果您解释一下原因,那么您的答案将对其他人更有用。 - Felix Kling
问题在于 myList.removeChild(myList.childNodes[ (counter) ]);,因为myList.childNodes节点返回8个值而不是4个。我们有一个包含4个节点的elements数组,因此从elements数组中删除会产生正确的结果。 - selvakumar
2
您可以编辑您的答案,包含那些信息。 - Felix Kling

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接