JS 将 child 附加到 class 的每个元素

JS Append child to each element of class

function makeCategory() {
    getList = document.getElementById("list");
    cat = document.createElement("div");
    cat.setAttribute("class", "cat");
    getList.appendChild(cat);
    cat.innerHTML =
        '<input type="text" name="name"/><span class="removeButton" onclick= "remove(this)">-</span><br><span class="makeSubCat" onclick="makeSubCategory(this)">+Category</span>';
}

function remove(z) {
    document.getElementById("list").removeChild(z.parentNode);
}

function makeSubCategory(i) {
    y = document.createElement("input");
    x = document.getElementsByClassName("cat");
    x[i].appendChild(y);
}

无法弄清楚如何使用 "onclick" 在 class 的每个元素上附加子元素。它不适用于 "for loop" - 它总是附加到最新的 div。它仅在我指定 class 元素的数量时有效。

演示大纲

  • 将 HTML 标签重写为真正的描述列表或 <dl>
  • 我们将通过点击事件来驱动函数,而不是尝试递归地操作多个元素
  • Event Delegation 的使用为我们节省了大量的额外代码。 <button><input> 的无限数量只需要一个 eventListener()
  • Template Literal 用于代替字符串文字
  • insertAdjacentHTML()add() 功能中发挥了重要作用

详情在演示中评论

演示

// Reference the Description List dl#list
var dock = document.getElementById("list");

/* Callback function
|| if the clicked button is NOT dl#list...
|| - tgt/e.target is the clicked <button>
|| - if tgt has .add, then call add()...
|| else if tgt has .rem...
|| cat is its parent (.cat)
|| - Get div.cat parent and remove .cat
*/
function mod(e, dock) {
  if (e.target !== e.currentTarget) {
    var tgt = e.target;
    if (tgt.className === 'add') {
      add.call(this, dock);
    } else if (tgt.className === 'rem') {
      var cat = tgt.parentNode;
      cat.parentNode.removeChild(cat);
    } else return;
  }
}

/* Register the ancestor of all of the .cat
|| and <button>s. (dl#list).
|| By doing this there's no need to addEventListeners
|| for every <button>
*/
dock.addEventListener('click', function(e) {
  mod(e, this);
}, false);

/* This function expression takes a string (in this
|| case the string is a Template Literal.) and
|| parses it into HTML as it inserts it at a 
|| position determined by the first parameter:
|| "beforeend" 
|| (exactly like append)
*/
var add = function(dock) {
  var cat = `<dd class='cat'>
              <input name="name" type='text'>
              <button class="rem">-</button>
              <button class="add">+</button>
             </dd>`;
  dock.insertAdjacentHTML('beforeend', cat);
};
#list {
  margin: 20px;
  border: 2px ridge gold;
  background: rgba(0, 0, 0, .3);
  padding: 5px 10px 15px;
}

dt {
  font: 700 20px/1 Consolas;
  color: gold;
  background: rgba(0, 0, 0, .5);
  padding: 5px;
}

dd {
  font-size: 16px;
  color: #fff;
  background: rgba(0, 0, 0, .5);
  padding: 5px;
  margin: 8px 4px 8px 0;
}

input,
button {
  width: 10%;
  font: inherit;
  display: inline-block;
}

input[type='text'] {
  width: 76%;
}
<dl id='list'>

  <dt>Category List</dt>

  <dd class='cat'>
    <input name="name" type='text'>
    <button class="add">+</button>
  </dd>

</dl>