首页 > 解决方案 > 如果使用javascript动态添加按钮,如何知道单击了哪个按钮?

问题描述

我不知道如何解决这个问题,如果有人知道如何解决,请告诉我。如果需要,我会亲自发送代码以找出错误。

有两个容器:左和右。在左侧,我从文本框和单选按钮(活动/非活动)中获取标题、描述和状态(活动/非活动)的值。然后在按下提交按钮后,所有值都填充到右侧容器表中,每次单击提交按钮后附加编辑和删除按钮。我想删除单击删除按钮的特定行。但是我不知道如何访问该按钮,而 onclick 功能(doDelete())在所有按钮中都是相同的。

function fillData() {
  var table = document.getElementById("myTable");
  var counter = table.querySelectorAll('tr').length;
  var key = counter;
  var row = table.insertRow(counter);
  row.id = "row-" + key;

  var titleCell = row.insertCell(0);
  var descCell = row.insertCell(1);
  var statusCell = row.insertCell(2);
  var actionCell = row.insertCell(3);

  var editButton = document.createElement("button");
  editButton.innerText = "Edit";
  editButton.id = "edit-" + key;
  editButton.setAttribute("onclick", "doEdit()");

  var delButton = document.createElement("button");
  delButton.innerText = "Delete";
  delButton.id = "delete-" + key;
  delButton.setAttribute("onclick", "doDelete()");

  titleCell.innerHTML = document.getElementById("panel-title").value;
  descCell.innerHTML = document.getElementById("panel-description").value;
  statusCell.innerHTML = (function () {
    var radios = document.getElementsByName("status");
    for (i = 0, len = radios.length; i < len; i++) {
      if (radios[i].checked) {
        return radios[i].value;
      }
    }
  }());

  actionCell.appendChild(editButton);
  actionCell.appendChild(delButton);

  var delBtnArr = document.querySelectorAll('input[type="button"]');
  console.log(delBtnArr);
}

实际结果:按下删除按钮后,整行都被删除。预期结果:按下删除按钮后,单击按钮的特定行将被删除。

标签: javascripthtml

解决方案


事件委托

将祖先绑定/注册到事件

动态添加的标签不能绑定到事件处理程序/侦听器,只有自页面加载以来已经存在的标签可以。因此,对于多个动态添加的标签(例如按钮),您必须找到它们都共享不常见的祖先标签并将其绑定到您需要侦听的任何事件。对于您的按钮,它可以是最接近的祖先table*(推荐)最远window

// On-event property. ALWAYS PASS THE EVENT OBJECT 
table.onclick = function(event) {...

或者

// Event Listener. Abbreviating the [Event Object][2] is OK, but you must be consistent.
table.addEventListener('click', function(e) {...

不要使用事件属性 <button onclick="func()"...

从技术上讲,最接近的祖先是tbody即使您没有将其添加到表中,浏览器也会默认添加它。


用途Event.targetEvent.currentTarget特性

请记住传递事件对象,因为您需要它来...

  • ...找出您实际使用event.target属性单击的按钮。

  • ...获取对具有event.currentTarget属性的表的引用。

  • ...可能会阻止默认行为,例如使用event.preventDefault()方法阻止表单提交到服务器。

查看演示,它将包含有关事件处理程序的特定详细信息。


演示

演示中评论的详细信息

var table = document.querySelector("table");

document.forms[0].onsubmit = fillData;

/*
This onevent property handler has two functions note it is bound 
to the table NOT the buttons.
There's two conditionals and they only focus on classNames of 
either .del or .edit. Once it's determined if the clicked tag has
one of these classes then the appropriate function is called.
If neither class was clicked there's no opportunity for anything
else to act on the click because both conditionals end with 
return false thereby terminating the event handler.
*/
table.onclick = function(e) {
  if (e.target.className === 'del') {
    delRow(e);
    return false;
  }
  if (e.target.className === 'edit') {
    editRow(e);
    return false;
  }
};

function fillData(e) {
  var ui = e.target.elements;
  e.preventDefault();
  var idx = table.rows.length;
  var row = table.insertRow();
  row.id = 'r-' + idx;

  var cell1 = row.insertCell(0);
  var data1 = ui.title.value;
  cell1.textContent = data1;

  var cell2 = row.insertCell(1);
  var data2 = ui.desc.value;
  cell2.textContent = data2;

  var cell3 = row.insertCell(2);
  var data3 = ui.chk.checked ? 'Active' : 'Inactive';
  cell3.textContent = data3;

  var cell4 = row.insertCell(3);
  var btns = `
  <button class='edit'>&#128221;</button>
  <button class='del'>&#10060;</button>`;
  cell4.innerHTML = btns;
}

/*
Reference the .closest() row from clicked button
Get that row's id and split() it at the dash and pop() the number.
Then get a reference to the bound ancestor (table) and deleteRow() with the new number you just got.
*/
function delRow(e) {
  var row = e.target.closest('tr');
  var idx = row.id.split('-').pop();
  e.currentTarget.deleteRow(idx);
}

/*
Same as before get the index number from the closest row's id.
Reference the table and use the .rows property and number.
This reference will now allow you to use the .cells property.
Use the .cells property to toggle the contenteditable attribute
on the first three cells.
*/
function editRow(e) {
  var row = e.target.closest('tr');
  var idx = row.id.split('-').pop();
  var R = e.currentTarget.rows[idx];
  for (let c = 0; c < 3; c++) {
    var cell = R.cells[c];
    if (cell.hasAttribute('contenteditable')) {
      cell.removeAttribute('contenteditable');
    } else {
      cell.setAttribute('contenteditable', true);
    }
  }
}
body {
  font: 400 16px/25px Consolas;
  display: flex;
  justify-content: space-between;
}

fieldset {
  width: fit-content
}

input,
label,
textarea {
  font: inherit
}

input,
label,
button {
  display: inline-block;
  height: 25px;
}

#title {
  width: 27.5ch;
}

#chk {
  display: none;
}

#chk+label::after {
  content: '\2610';
  font-size: 20px;
  vertical-align: middle;
}

#chk:checked+label::after {
  content: '\2611';
}

[type='reset'] {
  margin-left: 5%
}

td {
  min-width: 60px;
  border-bottom: 1px solid #000;
  height: 25px;
}

tr td:last-child {
  border-bottom-color: transparent;
}

button {
  width: 35px;
  text-align: center;
}
<form id='data'>
  <fieldset>
    <legend>Enter Data</legend>
    <input id='title' type='text' placeholder='Title'><br>
    <textarea id='desc' rows='3' cols='25' placeholder='Description'></textarea><br>
    <input id='chk' type='checkbox'>
    <label for='chk'>Active </label>
    <input type='reset'>
    <input type='submit'>
  </fieldset>
</form>

<hr>

<table></table>


推荐阅读