购物清单开发问题:新项编辑绑定与首行复选框禁用
TodoList 两个问题的解决方案
问题1:点击新增行复选框时首行复选框联动勾选的解决方法
问题根源
所有复选框的id都设为item_name_check,但HTML规范要求id必须唯一。点击新增行的<label>时,for属性会匹配页面中第一个该id的元素(即首行复选框),导致联动勾选。
修复步骤
- 修改初始HTML里的首行复选框id为
item_check_0,对应label的for属性同步更新; - 在
createItem函数中,利用全局id变量生成唯一的复选框id(如item_check_${id}),确保每个新项的复选框和label一一对应。
问题2:新增项目无法编辑的解决方法
问题根源
原代码仅给页面加载时存在的第一个.item_edit按钮绑定了事件,后续通过innerHTML新增的按钮未绑定事件;同时全局itemName变量始终指向首行文本元素,无法对应新增项。
修复步骤
采用事件委托机制,给父元素.items绑定点击事件,统一处理所有编辑按钮的交互:
- 删除原有的
editBTN变量及对应的事件监听; - 在
.items的点击事件中,判断点击目标是否为编辑按钮; - 针对当前点击项的
.item_name元素单独处理编辑逻辑,避免全局变量干扰。
修改后的完整代码
HTML代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>TodoList</title> <script src="script.js" defer></script> <script src="https://kit.fontawesome.com/dde5490d2b.js" crossorigin="anonymous"></script> <link rel="stylesheet" href="style.css" /> </head> <body> <section class="list"> <header class="header">Shopping List</header> <ul class="items"> <li class="item_row" data-id="0"> <div class="item"> <input type="checkbox" id="item_check_0" value="1"/> <label for="item_check_0" class="item_name">Egg</label> <div class="button_container"> <button class="item_edit">Edit</button> <button class="item_delete"> <i class="fas fa-trash-can" data-id="0"></i> </button> </div> </div> <div class="item_divider"></div> </li> </ul> <form class="new_form"> <footer class="footer"> <input type="text" class="footer_input" /> <button type="submit" class="footer_button"> <i class="fas fa-plus"></i> </button> </footer> </form> </section> </body> </html>
JS代码
const items = document.querySelector('.items'); const input = document.querySelector('.footer_input'); const form = document.querySelector('.new_form'); form.addEventListener('submit', (event) => { event.preventDefault(); onAdd(); }); function onAdd() { const text = input.value; if (text === '') { input.focus(); return; } const item = createItem(text); items.appendChild(item); item.scrollIntoView({ block: 'center' }); input.value = ''; input.focus(); } let id = 1; // 首行已使用id=0,从1开始计数 function createItem(text) { const itemRow = document.createElement('li'); itemRow.setAttribute('class', 'item_row'); itemRow.setAttribute('data-id', id); const checkboxId = `item_check_${id}`; itemRow.innerHTML = ` <div class="item"> <input type="checkbox" id="${checkboxId}" value="1"/> <label for="${checkboxId}" class="item_name">${text}</label> <div class="button_container"> <button class="item_edit" >Edit</button> <button class="item_delete" > <i class="fas fa-trash-alt" data-id=${id}></i> </button> </div> </div> <div class="item_divider"></div>`; id++; return itemRow; } items.addEventListener('click', (event) => { const target = event.target; // 处理删除逻辑 const deleteIcon = target.closest('.fas.fa-trash-alt'); if (deleteIcon) { const id = deleteIcon.dataset.id; const toBeDeleted = document.querySelector(`.item_row[data-id="${id}"]`); toBeDeleted.remove(); return; } // 处理编辑逻辑 const editBtn = target.closest('.item_edit'); if (editBtn) { const itemName = editBtn.closest('.item').querySelector('.item_name'); if (editBtn.innerText === 'Update') { const input = itemName.querySelector('.newItemInput'); itemName.innerText = input.value; editBtn.innerText = 'Edit'; } else { const currentText = itemName.innerText; itemName.innerHTML = ''; const newItemInput = document.createElement('input'); newItemInput.type = 'text'; newItemInput.className = 'newItemInput'; newItemInput.value = currentText; itemName.appendChild(newItemInput); newItemInput.focus(); editBtn.innerText = 'Update'; } } });
内容的提问来源于stack exchange,提问作者Chocolate covered Strawberry
相关产品推荐
相关产品推荐

