开发者问题收集

删除 div 后,添加 div 不起作用。为什么?

2023-02-15
94

我正在使用 HTML、CSS 和 JavaScript 制作一个费用跟踪器,我遇到了一个问题,当我第一次加载页面时,我可以添加任意数量的 div 项,但是当我删除其中一个(或多个)项后,添加按钮不再起作用。我在控制台中收到的错误是:

main.js:8 Uncaught TypeError: Cannot read properties of null (reading 'appendChild') at HTMLButtonElement.duplicate (main.js:8:25).

我有一个用于删除 div 的函数(在本例中,div 是列表中的费用项),称为 deleteItem(),另一个用于添加 div 的函数称为 duplicate()。我不确定发生了什么,但如果有人能帮忙,那就太好了。 我在 YouTube 上看到了一些使用 JQuery 的可能解决方案,但由于我仍在学习 JavaScript,所以我暂时不想涉及它。但是,如果解决方案需要 JQuery 或类似的东西,请告诉我。

document.getElementById('new-item-btn').onclick = duplicate;

var original = document.getElementById('expense-item');

function duplicate() {
  var clone = original.cloneNode(true);
  clone.id = "expense-item";
  original.parentNode.appendChild(clone);
}

function deleteItem() {
  var removeItem = document.getElementById('expense-item');
  removeItem.remove();
}
<main id="main">
  <div class="container" id="container">
    <div class="expense-item" id="expense-item">
      <button class="delete-btn" onclick="deleteItem()">Delete</button>
      <div class="expense-inputs">
        <label for="expense-name"></label>
        <input type="text" placeholder="Expense Name" id="expense-name">
        <label for="expense-category"></label>
        <select name="expense-category" id="expense-category">
          <option value="">Category</option>
          <option value="groceries">Groceries</option>
          <option value="housing">Housing</option>
          <option value="utilities">Utilities</option>
        </select>
        <label for="expense-amount"></label>
        <input type="text" id="expense-amount" name="expense-amount" placeholder="Amount">
      </div>
    </div>
  </div>
  <div class="info">
    <div class="new-item">
      <button class="new-item-btn" id="new-item-btn" onclick="duplicate()">New Item</button>
    </div>
  </div>
</main>
2个回答

要使删除方法动态化并且无需 id 即可工作,您可以这样做:

function deleteItem(obj) { // <- obj refers to the clicked object because of `this` in  onclick="deleteItem()"
  var removeItem = obj.parentElement; // <- use parentElement to target the "<div class="expense-item" id="expense-item">"
  removeItem.remove();
}

然后,您只需将 this 添加到 onclick="deleteItem()"

注意 我建议您在创建时仍将 id 更改为新内容,但这是删除方法的示例。

演示

document.getElementById('new-item-btn').onclick = duplicate;

var original = document.getElementById('expense-item');

function duplicate() {
  var clone = original.cloneNode(true);
  original.parentNode.appendChild(clone);
}

function deleteItem(obj) {
  var removeItem = obj.parentElement;
  removeItem.remove();
}
<main id="main">
  <div class="container" id="container">
    <div class="expense-item" id="expense-item">
      <button class="delete-btn" onclick="deleteItem(this)">Delete</button>
      <div class="expense-inputs">
        <label for="expense-name"></label>
        <input type="text" placeholder="Expense Name" id="expense-name">
        <label for="expense-category"></label>
        <select name="expense-category" id="expense-category">
          <option value="">Category</option>
          <option value="groceries">Groceries</option>
          <option value="housing">Housing</option>
          <option value="utilities">Utilities</option>
        </select>
        <label for="expense-amount"></label>
        <input type="text" id="expense-amount" name="expense-amount" placeholder="Amount">
      </div>
    </div>
  </div>
  <div class="info">
    <div class="new-item">
      <button class="new-item-btn" id="new-item-btn" onclick="duplicate()">New Item</button>
    </div>
  </div>
</main>
Carsten Løvbo Andersen
2023-02-15

在大多数情况下,您可以在创建动态内容时删除 ID,并使用其他方式识别 DOM 节点 - 例如将 querySelectorevent.target 结合使用。检查 Event 以确定点击的来源可能是最可靠的方法。

动态添加的内容事先不知道 ID 或其他属性,因此通过将 event 作为参数提供给 deleteItem 方法,您可以识别从按钮到容器的新添加的内容并轻松将其删除。

document.querySelector('.new-item-btn').onclick = duplicate;



function duplicate() {
  const original = document.querySelector('[data-id="expense-item"]');
  original.parentNode.appendChild( original.cloneNode(true) );
}

function deleteItem(e) {
  let item = e.target.closest('.expense-item');
  if( document.querySelectorAll('.expense-item').length > 1 ){
      item.parentNode.removeChild( item );
  }
}
<main>
  <div class="container">
  
    <div class="expense-item" data-id="expense-item">
      <button class="delete-btn" onclick="deleteItem(event)">Delete</button>
      <div class="expense-inputs">
        <label>
          <input type="text" placeholder="Expense Name" />
        </label>
        <label>
          <select name="expense-category" data-id="expense-category">
            <option value="">Category</option>
            <option value="groceries">Groceries</option>
            <option value="housing">Housing</option>
            <option value="utilities">Utilities</option>
          </select>
        </label>
        <label>
          <input type="text" name="expense-amount" placeholder="Amount" />
        </label>
      </div>
    </div>
    
  </div>

  <div class="info">
    <div class="new-item">
      <button class="new-item-btn" data-id="new-item-btn" onclick="duplicate()">New Item</button>
    </div>
  </div>
</main>
Professor Abronsius
2023-02-15