【问题标题】:addEventListener to button with JavaScript使用 JavaScript addEventListener 到按钮
【发布时间】:2021-12-14 09:04:10
【问题描述】:

在这段代码中,我使用了一个函数,该函数用 JSON 文件中的数据填充每个表行。我在表格的每一行附近添加了一个按钮。当我单击每个按钮时,我希望它执行一个功能(即使现在只是一个简单的警报)。这是我的代码:

function fillRow(employee){

var data = "";
var buttonCars = document.createElement("button");
var showCars = buttonCars.innerHTML = "show cars";

buttonCars.addEventListener("click", function() {
  alert('example alert');
});
        data =   "<tr>" + 
"<td>" + employee.name + "</td>" + 
"<td>" + employee.surname + "</td>" +
"<td>" + employee.email + "</td>" + 
"<td>" + "<button>" + showCars + "</button>" 
 + "</td>" + "</tr>";

return data;

}

现在,当我单击按钮时没有任何反应,我不明白为什么?

【问题讨论】:

  • 你在写document.createElement("button"),还手动写"&lt;button&gt;" + showCars + "&lt;/button&gt;"。因此,您正在创建两个按钮,一个以编程方式创建,一个在模板中。您正在将单击处理程序附加到以编程方式创建的处理程序上,该处理程序仅存在于内存中,并未添加到 DOM 中。您正在单击没有click 侦听器的模板按钮,因此没有任何反应。

标签: javascript html-table dom-events addeventlistener removeeventlistener


【解决方案1】:

您正在向buttonCars 添加一个事件处理程序,但没有将buttonCars 放在页面的任何位置;它无法在函数返回后继续存在。你的函数只返回一个 HTML 字符串(没有那个按钮),所以它不能通过addEventListener 连接一个事件处理程序(它可以通过onxyz-attribute-style 事件处理程序的方式,通常是不好的做法) .

相反,让您的函数返回一个实际的 tr 元素及其行和按钮:

function fillRow(employee){
    const tr = document.createElement("tr");
    tr.innerHTML = `
        <td>${employee.name}</td>
        <td>${employee.surname}</td>
        <td>${employee.email}</td>
        <td><button>show cars</button></td>`;
    tr.querySelector("button").addEventListener("click", function() {
        alert("example alert");
    });
    return tr;
}

请注意,这会改变您使用来自fillRow 的返回值的方式,因为它返回的是实际元素,而不是字符串。因此,您会将其附加到 tbody 元素(通常)而不是将其视为 HTML。

以下是创建短表的示例:

function fillRow(employee){
    const tr = document.createElement("tr");
    tr.innerHTML = `
        <td>${employee.name}</td>
        <td>${employee.surname}</td>
        <td>${employee.email}</td>
        <td><button type="button">show cars</button></td>`;
    tr.querySelector("button").addEventListener("click", function() {
        alert("example alert");
    });
    return tr;
}

const employees = [
    {name: "Joe", surname: "Bloggs", email: "joe@example.com"},
    {name: "Muhammad", surname: "Abu-Yasein", email: "muhammad@example.com"},
    {name: "María", surname: "Gutierrez", email: "maría@example.com"},
];

const tbody = document.getElementById("table-body");

// Add the already-known employees
// (Generally best when doing lots of appends to use a document fragment
// or, in modern environments, the new `append` method that lets you
// provide multiple elements (https://developer.mozilla.org/en-US/docs/Web/API/Element/append),
// to avoid multiple distinct DOM modifications.)
tbody.append(...employees.map(fillRow));
/* Here's what it looks like with a fragment
const frag = document.createDocumentFragment();
for (const employee of employees) {
    frag.appendChild(fillRow(employee));
}
tbody.appendChild(frag); // Appends the fragment's children, not the fragment
*/

// Allow adding new ones
document.getElementById("btn-add").addEventListener("click", function() {
    const name = document.getElementById("new-name").value;
    const surname = document.getElementById("new-surname").value;
    const email = document.getElementById("new-email").value;
    const employee = {
        name, surname, email
    };
    employees.push(employee);
    tbody.appendChild(fillRow(employee));
});
label {
    display: grid;
    grid-template-columns: 1fr 2fr;
}
table {
    border: 1px solid black;
}
<table>
    <thead>
        <th>Name</th>
        <th>Surname</th>
        <th>email</th>
        <th></th>
    </thead>
    <tbody id="table-body"></tbody>
</table>
<hr>
<div>
    <label>
        Name:
        <input type="text" id="new-name">
    </label>
</div>
<div>
    <label>
        Surname:
        <input type="text" id="new-surname">
    </label>
</div>
<div>
    <label>
        Email:
        <input type="text" id="new-email">
    </label>
</div>
<input type="button" value="Add" id="btn-add">

(这在表单中使用了很多ids,我通常不会这样做,但对于示例来说它又快又容易。)

【讨论】:

    【解决方案2】:

    我可以建议两种不混合 HTML 和 JavaScript 代码的方法吗?

    方法 1:ad hoc 代码

    一种相对简单的方法,其中函数紧密绑定到您要填充的特定表

    function addCell(data) {
      const tdElem = document.createElement('td');
      if (data instanceof HTMLElement) {
        tdElem.append(data);
      } else {
        tdElem.innerText = data
      }
      return tdElem;
    }
    
    function handleCarBtnClick(employeeId) {
      window.alert(`${employeeId}'s car`)
    }
    
    function fillEmployeeRow(employeeData) {
      const trElem = document.createElement('tr');
      const btnCarElem = document.createElement('button');
      btnCarElem.innerText = 'show cars';
      btnCarElem.addEventListener('click', () => handleCarBtnClick(employeeData.name));
    
      trElem.append(addCell(employeeData.name));
      trElem.append(addCell(employeeData.surname));
      trElem.append(addCell(employeeData.email));
      trElem.append(addCell(btnCarElem));
    
      document.querySelector('#employees-table').append(trElem);
    }
    
    // Populating the employees table
    
    [{
        name: 'John',
        surname: 'Doe',
        email: 'john.doe@email.tld'
      },
      {
        name: 'Jane',
        surname: 'Doe',
        email: 'jane.doe@email.tld'
      },
      {
        name: 'Foo',
        surname: 'Bar',
        email: 'foo.bar@email.tld'
      }
    ].forEach(employee => fillEmployeeRow(employee))
    <table id='employees-table'>
      <tr>
        <th>Name</th>
        <th>Surname</th>
        <th>E-mail</th>
        <th>Cars</th>
      </tr>
    </table>

    方法 2:可重用的泛型函数

    我承认,对于这样一个简单的案例来说,这可能有点矫枉过正,但只是为了好玩和促进良好 (?) 做法......

    // Reusable functions
    
    function addCell(data) {
      const tdElem = document.createElement('td');
      if (data instanceof HTMLElement) {
        tdElem.append(data);
      } else {
        tdElem.innerText = data
      }
      return tdElem;
    }
    
    function addRow(data, fields, targetTable) {
      const trElem = document.createElement('tr');
      fields.forEach(field => trElem.append(addCell(data[field])));
      targetTable.append(trElem);
    }
    
    function addButton(btnText, btnClickHandler) {
      const btnElem = document.createElement('button');
      btnElem.innerText = btnText;
      btnElem.addEventListener('click', btnClickHandler);
      return btnElem;
    }
    
    // Populating the two tables using the same functions
    
    // Employees table
    
    function handleCarBtnClick(employeeId) {
      window.alert(`${employeeId}'s car`)
    }
    
    [{
        name: 'John',
        surname: 'Doe',
        email: 'john.doe@email.tld',
        salary: 30000
      },
      {
        name: 'Jane',
        surname: 'Doe',
        email: 'jane.doe@email.tld',
        salary: 30000
      },
      {
        name: 'Foo',
        surname: 'Bar',
        email: 'foo.bar@email.tld',
        salary: 30000
      }
    ].forEach(employee => {
      const args = {
        data: {
          ...employee,
          btn: addButton('show cars', () => handleCarBtnClick(employee.name))
        },
        fields: ['name', 'surname', 'email', 'btn'],
        targetTable: document.querySelector('#employees-table')
      };
    
      addRow(args.data, args.fields, args.targetTable)
    });
    
    // Departments table
    [{
        name: 'Sales',
        location: '2nd floor, Building A',
        phone: '123456789'
      },
      {
        name: 'Marketing',
        location: '2nd floor, Building A',
        phone: '123456789'
      },
      {
        name: 'Human Resources',
        location: '1st floor, Building A',
        phone: '123456789'
      }
    ].forEach(department => {
      addRow(department, ['name', 'location'], document.querySelector('#departments-table'));
    });
    <table id='employees-table'>
      <tr>
        <th>Name</th>
        <th>Surname</th>
        <th>E-mail</th>
        <th>Cars</th>
      </tr>
    </table>
    
    <hr />
    
    <table id='departments-table'>
      <tr>
        <th>Name</th>
        <th>Location</th>
      </tr>
    </table>

    【讨论】:

      猜你喜欢
      • 2022-11-23
      • 1970-01-01
      • 2021-06-10
      • 1970-01-01
      • 2021-02-08
      • 1970-01-01
      • 1970-01-01
      • 2017-06-02
      • 2018-12-09
      相关资源
      最近更新 更多