Javascript DOM removeChild 和 addEventListener 的操作错误

Javascript DOM Manipulation error with removeChild and addEventListener

我基本上是在构建一个非常简单的列表。在顶部的输入字段中输入内容,单击按钮,它会出现在下方的 ul 中。

我的控制台出现两个错误,我不太确定我做错了什么。

首先,在第 12 行,这个事件侦听器:

deleteBtn.addEventListener('click', removeItem);

错误显示 "Cannot read property 'addEventListener' of null",我相信这是因为加载时 deleteBtn 不在页面上,当您将项目添加到列表时,它被添加到带有 li 的 DOM 中。

其次,第 40 行:

selectedItem.removeChild(checkMark);

错误显示 "Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node."

这是我的全部代码:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Bootstrap Crash Course</title>

  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css"
        integrity="sha384-PsH8R72JQ3SOdhVi3uxftmaW6Vc51MKb0q5P2rRUpPvrszuE4W1povHYgTpBfshb"
        crossorigin="anonymous" />
  <link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"
        integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN"
        crossorigin="anonymous">

  <style type="text/css">
    #myButton {
      cursor: pointer;
    }

    .input-group {
      margin: 15px 0;
    }

    .fa-times-circle-o {
      font-size: 24px;
      cursor: pointer;
    }

    .fa-check-circle {
      font-size: 24px;
    }

  </style>
</head>
<body>

<div class="container">

  <div class="input-group">
    <input type="text" class="rounded form-control" id="myInput" />
    <span id="myButton" class="input-group-addon">Click</span>
  </div>

  <ul class="list-group" id="myOutput">

  </ul>

</div> <!-- .containter -->




  <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"
          integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN"
          crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.3/umd/popper.min.js"
          integrity="sha384-vFJXuSJphROIrBnz7yo7oB41mKfc8JzQZiCq4NCceLEaO4IHwicKwpJf9c9IpFgh"
          crossorigin="anonymous"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/js/bootstrap.min.js"
          integrity="sha384-alpBpkh1PFOepccYVYDB4do5UnbKysX5WZXm3XxPqe5iKTfUKjNkCk9SaVuEZflJ"
          crossorigin="anonymous"></script>
  <script src="app.js"></script>
</body>
</html>

//Code from app.js

let myButton = document.getElementById('myButton');
let myOutput = document.getElementById('myOutput');
let myInput = document.getElementById('myInput');
let listGroupItems = document.querySelectorAll('.list-group-item');
let deleteBtn = document.getElementById('deleteBtn');

setUpEventListeners();

function setUpEventListeners() {
  myButton.addEventListener('click', addItem);
  myOutput.addEventListener('click', toggleItem);
  deleteBtn.addEventListener('click', removeItem);
}

function addItem() {
  if (myInput.value === '') {
    console.log('Field is empty!');
  } else {
    let li = document.createElement('li');
    let inputValue = document.createTextNode(myInput.value);

    li.innerHTML = '<i class="fa fa-times-circle-o float-right" aria-hidden="true" id="deleteBtn"></i>';
    li.className = 'list-group-item';
    myOutput.appendChild(li);
    li.appendChild(inputValue);
  }
  myInput.value = '';
}

function toggleItem(e) {
  let selectedItem = e.target;
  let checkMark = document.createElement('i');
  checkMark.classList.add('fa', 'fa-check-circle', 'float-left');

  console.log(selectedItem);

  if (selectedItem.classList.contains('bg-success') && selectedItem.classList.contains('list-group-item')) {
    selectedItem.classList.remove('bg-success');
    selectedItem.classList.remove('text-white');
    //listGroupItems.removeChild(checkMark);
  } else if (!selectedItem.classList.contains('bg-success') && selectedItem.classList.contains('list-group-item')) {
    selectedItem.classList.add('bg-success');
    selectedItem.classList.add('text-white');
    selectedItem.appendChild(checkMark);
  }
}

function removeItem() {
  e.target.parentElement.remove();
}

deleteBtn 变量未定义,因为您在页面加载时没有至少一个 ID 为 deleteBtn 的项目。

不是在创建按钮之前将事件添加到 deleteBtn,而是在创建按钮时使用 onclick 添加内联事件并调用函数 removeItem 并使用 [=16 传递上下文=]

对于第二个问题listGroupItems是一个数组。所以数组中没有removeChild方法。

要解决第二个问题,请从 childNodes collection.Then 中获取图标的索引,使用该索引删除此特定子项

let myButton = document.getElementById('myButton');
let myOutput = document.getElementById('myOutput');
let myInput = document.getElementById('myInput');
let listGroupItems = document.querySelectorAll('.list-group-item');


setUpEventListeners();

function setUpEventListeners() {
  myButton.addEventListener('click', addItem);
  myOutput.addEventListener('click', toggleItem);

}

function addItem() {
  if (myInput.value === '') {
    console.log('Field is empty!');
  } else {
    let li = document.createElement('li');
    let inputValue = document.createTextNode(myInput.value);
    // Changed here adding onclick
    li.innerHTML = '<i class="fa fa-times-circle-o float-right" aria-hidden="true" onclick="removeItem(this)" class="deleteBtn"></i>';
    li.className = 'list-group-item';
    myOutput.appendChild(li);
    li.appendChild(inputValue);

  }
  myInput.value = '';
}

function toggleItem(e) {
  let selectedItem = e.target;
  if (selectedItem.classList.contains('bg-success') && selectedItem.classList.contains('list-group-item')) {
    selectedItem.classList.remove('bg-success');
    selectedItem.classList.remove('text-white');
    var iconIndex = '';
    // getting the index of the icon which have the specifc class from childNodes using its class
    for (var i = 0; i < selectedItem.childNodes.length; i++) {
      if (selectedItem.childNodes[i].className === "fa fa-check-circle float-left") {
        iconIndex = i;
      }
    }
    // Using that index to remove the icon child
    selectedItem.removeChild(selectedItem.childNodes[iconIndex]);
  } else if (!selectedItem.classList.contains('bg-success') && selectedItem.classList.contains('list-group-item')) {
    let checkMark = document.createElement('i');
    checkMark.classList.add('fa', 'fa-check-circle', 'float-left');
    selectedItem.classList.add('bg-success');
    selectedItem.classList.add('text-white');
    selectedItem.appendChild(checkMark);
  }
}

function removeItem(elem) {
  elem.parentNode.remove();
}
#myButton {
  cursor: pointer;
}

.input-group {
  margin: 15px 0;
}

.fa-times-circle-o {
  font-size: 24px;
  cursor: pointer;
}

.fa-check-circle {
  font-size: 24px;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css" integrity="sha384-PsH8R72JQ3SOdhVi3uxftmaW6Vc51MKb0q5P2rRUpPvrszuE4W1povHYgTpBfshb" crossorigin="anonymous" />
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous" />
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.3/umd/popper.min.js" integrity="sha384-vFJXuSJphROIrBnz7yo7oB41mKfc8JzQZiCq4NCceLEaO4IHwicKwpJf9c9IpFgh" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/js/bootstrap.min.js" integrity="sha384-alpBpkh1PFOepccYVYDB4do5UnbKysX5WZXm3XxPqe5iKTfUKjNkCk9SaVuEZflJ" crossorigin="anonymous"></script>

<div class="container">

  <div class="input-group">
    <input type="text" class="rounded form-control" id="myInput" />
    <span id="myButton" class="input-group-addon">Click</span>
  </div>

  <ul class="list-group" id="myOutput">

  </ul>

</div>

删除一个元素使用removeChild()方法,签名是:

parentOfTarget.removeChild(target)

在下面的演示中,Template Literals and insertAdjacentHTML() was used to consolidate element creation and insertion into the DOM. BTW you can't assign an id to an element that's created multiple times. ids are unique so #deleteBtn was removed. An id isn't needed on the buttons if you delegate events 无论如何。

有大量的 classes 进行和关闭,所以我将它们放在数组中,然后在 forEach()

的每次迭代中切换每个 class

Demo中有详细说明

演示

var xBtn = document.getElementById('xButton');
var xOut = document.getElementById('xOutput');
var xInp = document.getElementById('xInput');

xBtn.addEventListener('click', addItem);
xOut.addEventListener('click', iconClick);

function addItem() {
  if (xInp.value === '') {
    console.log('Field is empty!');
  } else {
    /* This is a Template Literal which is a string
    || with powerful syntax and methods
    */
    let li = `<li class='list-group-item'>
    <i class="fa fa-circle-o float-left"></i>
    &nbsp;${xInp.value}&nbsp;
    <i class="fa fa-times-circle-o float-right"></i>
    </li>`;

    // Use insertAdjacentHTML() instead of innerHTML
    xOut.insertAdjacentHTML('beforeend', li);
  }
  xInp.value = '';
}

function iconClick(e) {

  // Reference e.target
  var tgt = e.target;
  // Reference e.target's parent
  var item = tgt.parentElement;

  /* if e.target has class .float-left
  || forEach() will...
  */
  if (tgt.classList.contains('float-left')) {

    // toggle e.target's FA icon classes
    ['fa-check-circle', 'fa-circle-o'].forEach(function(c, idx) {
      tgt.classList.toggle(c);
    });

    // toggle e.target's parent's state classes
    ['bg-success', 'text-white'].forEach(function(i, idx) {
      item.classList.toggle(i);
    });

    /* ...but if it has class .float-right
    || remove the parent of e.target by referencing
    || the parent of the parent of e.target (grandma)
    */
  } else if (tgt.classList.contains('float-right')) {
    xOut.removeChild(item);

    // ...otherwise just end function
  } else {
    return false;
  }
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Bootstrap Crash Course</title>

  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css">
  <link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">

  <style>
    #xButton {
      cursor: pointer;
    }
    
    .input-group {
      margin: 15px 0;
    }
    
    .fa {
      font-size: 24px;
      cursor: pointer;
    }
  </style>
</head>

<body>

  <div class="container">

    <div class="input-group">
      <input type="text" class="rounded form-control" id="xInput" />
      <button id="xButton" class="btn btn-primary input-group-addon">ADD</button>
    </div>

    <ul class="list-group" id="xOutput">

    </ul>

  </div>
  <!-- .containter -->




  <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.3/umd/popper.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/js/bootstrap.min.js"></script>

</body>

</html>