如何阻止长按函数在首次触发后对后续li元素生效?
问题解决:长按列表项后停止长按逻辑触发
需求说明
- 长按
<li>元素时,切换该元素的active类,并将其父<ul>的data-edit属性设为true - 当
data-edit="true"时,点击任意<li>即可直接切换active状态,无需长按
现有代码
HTML
<ul class="container" data-edit="false"> <li class="item" tabindex="0"></li> <li class="item" tabindex="0"></li> <li class="item" tabindex="0"></li> </ul>
JavaScript
function longPress() { const lists = document.querySelectorAll("[data-edit=false]"); const delay = 800; lists.forEach((list) => { const listItems = list.querySelectorAll("li"); listItems.forEach((listItem) => { listItem.addEventListener("mouseup", () => { clearTimeout(pressTimer); }); listItem.addEventListener("mousedown", () => { pressTimer = setTimeout(() => { listItem.classList.toggle("active"); list.setAttribute("data-edit", "true"); }, delay); }); }); }); }
存在问题
长按某个<li>后,父<ul>的data-edit已设为true,但之前绑定的长按事件并未移除,导致后续长按其他<li>时仍会触发切换逻辑,不符合编辑模式下无需长按的需求。
解决方案
方法1:事件委托+动态解绑(推荐)
通过事件委托将事件绑定到<ul>上,触发长按后直接移除该<ul>的长按事件,同时添加编辑模式的点击事件:
function initListEdit() { const delay = 800; let pressTimer; document.querySelectorAll('[data-edit=false]').forEach(list => { // 定义长按相关事件处理函数 const handleMouseDown = (e) => { const targetLi = e.target.closest('li'); // 不是li元素或已进入编辑模式,直接返回 if (!targetLi || list.dataset.edit === 'true') return; pressTimer = setTimeout(() => { targetLi.classList.toggle('active'); list.dataset.edit = 'true'; // 移除长按相关事件,避免后续触发 list.removeEventListener('mousedown', handleMouseDown); list.removeEventListener('mouseup', handleMouseUp); list.removeEventListener('mouseleave', handleMouseUp); // 添加编辑模式的点击切换事件 list.addEventListener('click', (e) => { const li = e.target.closest('li'); if (li) li.classList.toggle('active'); }); }, delay); }; const handleMouseUp = () => { clearTimeout(pressTimer); }; // 绑定事件 list.addEventListener('mousedown', handleMouseDown); list.addEventListener('mouseup', handleMouseUp); // 补充鼠标离开事件,防止移开后仍触发长按 list.addEventListener('mouseleave', handleMouseUp); }); } // 初始化调用 initListEdit();
方法2:解绑单个列表项的事件
如果保留原有的列表项绑定方式,可在触发长按后移除所有<li>的长按事件,再添加点击事件:
function longPress() { const lists = document.querySelectorAll("[data-edit=false]"); const delay = 800; lists.forEach((list) => { let pressTimer; const listItems = list.querySelectorAll("li"); // 定义可复用的事件处理函数 const handleMouseUp = () => { clearTimeout(pressTimer); }; const handleMouseDown = (e) => { const listItem = e.target; pressTimer = setTimeout(() => { listItem.classList.toggle("active"); list.setAttribute("data-edit", "true"); // 移除所有列表项的长按相关事件 listItems.forEach(item => { item.removeEventListener('mouseup', handleMouseUp); item.removeEventListener('mousedown', handleMouseDown); item.removeEventListener('mouseleave', handleMouseUp); }); // 添加编辑模式的点击切换事件 listItems.forEach(item => { item.addEventListener('click', () => { item.classList.toggle('active'); }); }); }, delay); }; // 绑定初始事件 listItems.forEach((listItem) => { listItem.addEventListener("mouseup", handleMouseUp); listItem.addEventListener("mousedown", handleMouseDown); listItem.addEventListener("mouseleave", handleMouseUp); }); }); }
核心思路
- 触发首次长按后,立即移除原来的长按事件绑定,阻止后续长按逻辑执行
- 同步添加编辑模式的点击事件,满足点击切换状态的需求
- 补充
mouseleave事件处理,避免用户长按过程中移开鼠标仍触发长按逻辑
内容的提问来源于stack exchange,提问作者Nicola Friuli
相关产品推荐
相关产品推荐

