jQuery Todo应用点击事件堆叠问题求助
问题分析与解决方案
问题根源
你遇到的多次弹窗问题,核心原因是编辑操作时的keydown事件被重复绑定且未解绑:
- 每次按下Alt键点击待办项时,都会给
document绑定一个新的keydown事件处理函数,这些事件会持续累积。 - 即使待办项被重新渲染(DOM元素替换),绑定在
document上的事件引用依然存在,后续操作可能触发多个事件处理函数,导致多次弹出确认框。 - 另外,
checkTodos函数中错误使用了$('#notices')选择器,而HTML中对应的元素ID是todo-notices,会导致通知无法正常显示。
修复方案
- 使用
.one()绑定编辑的keydown事件:直接给目标待办项绑定keydown事件,并设置仅触发一次,触发后自动解绑,避免事件累积。 - 修复通知选择器:将
$('#notices')改为$('#todo-notices')。 - 增加ESC键取消编辑功能:提升用户体验,允许用户按下ESC键放弃编辑。
修改后的完整代码
HTML部分
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.4/jquery.min.js" integrity="sha512-pumBsjNRGGqkPzKHndZMaAG+bir374sORyzM3uulLV14lN5LyykqNk8eEeUlUkB3U0M4FApyaHraT65ihJhDpQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> <div id="container"> <header> <div id="title">Todo List</div> </header> <nav></nav> <aside> <input id="todo" type="text" placeholder="Add new items here." /> </aside> <main> <div class="container"> <!-- incomplete todo --> <div id="todo-incomplete"></div> </div> <div id="todo-notices"></div> <div id="todo-notes"> <p class="text-info">Edit Item - Windows: Alt-click; Mac: Option-click</p> <p class="text-info">Delete Item - Shift-click</p> </div> </main> <footer> <div id="copyright"></div> <div id="page-load"></div> </footer> </div>
JavaScript部分
function checkTodos() { var list = JSON.parse(localStorage['todo-list']); if (list.length == 0) { // 修复选择器错误 $('#todo-notices').html(`<div class='card'>No list items exist yet. Use the input box on the left to add items.</div>`); } else { let html = ""; list.forEach((todo, index) => { html += `<div id='item-${index}' class='card' data-index='${index}'>${todo}</div>`; }); $("#todo-incomplete").html(html); // 修复选择器错误 $('#todo-notices').empty(); } } function updateTodos(list) { $('#todo').val(''); localStorage.setItem('todo-list', JSON.stringify(list)); checkTodos(); } function doConfirm(type = 'delete') { let message = type == 'delete' ? 'Do you confirm todo item deletion?' : 'Do you confirm todo item editing?'; return confirm(message); } $(document).ready(function() { let list; if (localStorage) { list = localStorage.hasOwnProperty('todo-list') ? JSON.parse(localStorage['todo-list']) : []; } checkTodos(); // 新增待办项 $(document).on('keydown', '#todo', (event) => { if (event.which === 13 && $(event.target).val() !== "") { list.push($(event.target).val()); updateTodos(list); } }); // 待办项点击事件 $(document).on('click', '#todo-incomplete > .card', (event) => { event.preventDefault(); if (event.shiftKey) { // 删除待办项 if (doConfirm()) { const index = parseInt($(event.target).attr('data-index')); list.splice(index, 1); updateTodos(list); } } else if (event.altKey) { // 编辑待办项 const $target = $(event.target); $target.attr('contenteditable', true); $target.focus(); // 使用.one()绑定keydown事件,确保仅触发一次 $target.one('keydown', (e) => { if (e.which === 13) { // 回车确认编辑 e.preventDefault(); // 避免添加换行符 if (doConfirm('edit')) { $target.removeAttr('contenteditable'); const index = parseInt($target.attr('data-index')); list[index] = $target.html(); updateTodos(list); } else { // 取消编辑,恢复原内容 $target.removeAttr('contenteditable'); $target.html(list[index]); } } else if (e.which === 27) { // ESC取消编辑 e.preventDefault(); $target.removeAttr('contenteditable'); $target.html(list[index]); } }); } else { console.log(event.which); } }); });
关键修改说明
- 编辑操作的keydown事件改为直接绑定在目标元素上,并使用
.one(),确保事件仅执行一次后自动解绑,彻底解决事件累积问题。 - 修复了通知区域的选择器错误,确保空列表提示正常显示。
- 增加了ESC键取消编辑的逻辑,同时在用户取消编辑确认时恢复原内容,提升体验。
- 删除了不必要的
event.stopPropagation(),因为事件委托绑定在document上,该方法无法阻止事件到达document。
内容的提问来源于stack exchange,提问作者JLDN Admin
相关产品推荐
相关产品推荐

