简体   繁体   English

使用 JavaScript 将事件侦听器添加到按钮

[英]addEventListener to button with JavaScript

In this code I'm into a function that fills each table row with data from a JSON file.在这段代码中,我使用了一个函数,该函数用来自 JSON 文件的数据填充每个表行。 I added a button near each row of the table.我在表格的每一行附近添加了一个按钮。 When I click each button I want it to perform a function (even just a simple alert at the moment).当我单击每个按钮时,我希望它执行一项功能(目前甚至只是一个简单的警报)。 This is my code:这是我的代码:

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;

}

Right now, nothing happens when I click the button and I don't understand why?现在,当我单击按钮时什么也没有发生,我不明白为什么?

You're adding an event handler to buttonCars , but not putting buttonCars in the page anywhere;您正在向buttonCars添加一个事件处理程序,但没有将buttonCars放在页面中的任何位置; it doesn't survive the return of the function.它不会在函数返回后继续存在。 Your function just returns a string of HTML (without that button), so it can't hook up an event handler via addEventListener (and the way it can, onxyz -attribute-style event handlers, is generally poor practice).您的函数只返回一个 HTML 字符串(没有那个按钮),所以它不能通过addEventListener连接事件处理程序(它可以的方式, onxyz -attribute-style 事件处理程序,通常是不好的做法)。

Instead, have your function return an actual tr element with its rows and the button:相反,让您的函数返回一个实际的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;
}

Note that this changes how you use the return value from fillRow , because it returns an actual element, not a string.请注意,这会改变您使用fillRow返回值的fillRow ,因为它返回的是实际元素,而不是字符串。 So you'd append it to a tbody element (typically) rather than treating it as HTML.因此,您会将其附加到tbody元素(通常)而不是将其视为 HTML。

Here's an example creating a short table:这是创建一个短表的示例:

 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">

(That uses a lot of id s for the form, which I don't normally, but it's quick and easy for the example.) (这在表单中使用了很多id ,我通常不会这样做,但对于示例来说它既快速又简单。)

May I suggest two approaches that do not mix HTML and JavaScript code?我可以建议两种不混合 HTML 和 JavaScript 代码的方法吗?

Approach 1: ad hoc code方法 1:即席代码

A relatively simple approach where the functions are tightly bound to the specific table you want to populate一种相对简单的方法,其中函数与您要填充的特定表紧密绑定

 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>

Approach 2: reusable generic functions方法二:可重用的泛型函数

I admit this is probably an overkill for such a simple case but, just for fun and for the sake of promoting good (?) practices...我承认这对于这样一个简单的案例来说可能有点矫枉过正,但是,只是为了好玩和为了促进良好的(?)实践......

 // 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>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM