for循环和remove()的细节

时间:2019-03-16 13:47:49

标签: javascript jquery

我有多个html元素,其中包含一个数字。
每次单击按钮都会将该数字减少-1。
当数字等于0时,必须删除元素。

我的代码仅删除了一半的元素,我不明白为什么...
JsFiddle DEMO

<div class='moo'>3</div>
<div class='moo'>3</div>
<div class='moo'>3</div>
<div class='moo'>3</div>
<div class='moo'>3</div>
<div class='moo'>3</div>
<div class='moo'>3</div>
<div class='moo'>3</div>
<div class='moo'>50</div>

<button id='bubu'>Remove</button>

JS:

$(document).on('click','#bubu',function(){
  var x = document.getElementsByClassName('moo');
  for(var i = 0; i < x.length; i++){
    if( Number(x[i].innerHTML) > 0 ) {
      x[i].innerHTML = Number(x[i].innerHTML) - 1;
    }
    if( Number(x[i].innerHTML) == 0 ){
      x[i].remove();
    } 
  }
});

(i)用replace和innerHTML删除是不可能的,这是一个简化的html。

2 个答案:

答案 0 :(得分:2)

这是因为当您删除项目时,x节点列表的长度会变小,并且您使用该长度作为循环条件,直到。

如果从节点列表的末尾删除项目并向后工作,则此方法将起作用,因为从末尾删除允许循环条件缩小,而无需跳过节点列表中的任何元素:

$(document).on('click','#bubu',function(){
  var x = document.getElementsByClassName('moo');
  for(var i = x.length-1; i >= 0 ; i--){
    if( Number(x[i].innerHTML) > 0 ) {
      x[i].innerHTML = Number(x[i].innerHTML) - 1;
    }
    if( Number(x[i].innerHTML) == 0 ){
      x[i].remove();
    } 
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class='moo'>3</div>
<div class='moo'>3</div>
<div class='moo'>3</div>
<div class='moo'>3</div>
<div class='moo'>3</div>
<div class='moo'>3</div>
<div class='moo'>50</div>
<div class='moo'>3</div>
<div class='moo'>3</div>
<button id='bubu'>Remove</button>

话虽如此,但是您的方法存在许多问题:

.getElementsByClassName()返回“活动”节点列表,实际上不应该使用。阅读another post of mine,其中会对此进行详细说明。

.innerHTML具有安全和性能方面的意义,仅当您使用的字符串包含HTML时才应使用。如果字符串中没有HTML,请使用.textContent

使用数组及其内置的.forEach()方法进行迭代,而不是依赖于必须通过循环管理的数字计数器。

这是相同的结果,以更加简洁和高效的方式完成:

$('#bubu').on('click', function(){
  // Get the elements into an Arrray without a live node list
  var elements = Array.prototype.slice.call(document.querySelectorAll(".moo"));
  
  // Loop over the array
  elements.forEach(function(element){
    // Get the text of the element and convert to a number. The prepended + symbol does this.
    let elNum = +element.textContent;
    
    // Instead of two consecutive if/then statements, use one with an else if
    if(elNum > 0) {
      element.textContent = --elNum;  // Just set the content to 1 less
    } else if(elNum === 0){
      element.remove();
    }
  });
});
.moo { display:inline-block; font-size:1.5em; color:#f00; border:1px solid grey; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class='moo'>3</div>
<div class='moo'>3</div>
<div class='moo'>4</div>
<div class='moo'>3</div>
<div class='moo'>3</div>
<div class='moo'>3</div>
<div class='moo'>50</div>
<div class='moo'>3</div>
<div class='moo'>5</div>
<button id='bubu'>Remove</button>

答案 1 :(得分:1)

getElementsByClassName返回一个动态集合,因此当您从DOM中删除项目时,集合的大小会减小,解决此问题的最简单方法是将集合隐式转换为标准数组

import 'package:flutter/material.dart';

import 'package:http/http.dart' as http;
import 'package:webfeed/webfeed.dart';

class Food extends StatelessWidget{
  final client = http.Client();


  rssStream(){
    client.get("https://developer.apple.com/news/releases/rss/releases.rss").then((response) {
      return response.body;
    }).then((bodyString) {
      var channel = new RssFeed.parse(bodyString);
      print(channel);
      return channel;
    });
}

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        leading: Image.asset('assets/icon.png'),
        title: Text('App'),
      ),
      body: rssStream(),
    );
  }
}