JavaScript单次点击添加两次Div元素问题排查与解决
问题产生原因
- 核心触发点:每次点击设计按钮调用
begin_design函数时,都会给canvas元素新增一个mousedown事件监听器,多次切换设计/编辑模式就会重复绑定多组相同的监听。触发点击时所有绑定的监听函数都会执行,所以切换编辑后再回设计模式,单次点击会同时生成2个圆形,切换次数越多生成的圆形数量也会同步增加。 - 附带隐患:
edit_design函数同样存在重复绑定问题,每次点击编辑按钮都会给canvas重复绑定mouseup、mousemove事件,给所有已生成的圆形重复绑定mousedown事件,会导致拖拽逻辑多次执行、出现卡顿或拖拽异常。
修复方案
推荐采用「全局事件单次绑定+状态变量控制逻辑执行」的方案,不需要反复绑定/解绑事件,改造成本低、稳定性高:
- 移除按钮点击事件中对
begin_design、edit_design的调用,按钮点击只负责切换状态和样式 - 所有事件监听只在页面初始化时绑定一次,通过
isDesign、isEdit变量控制对应逻辑是否生效 - 新建圆形时直接绑定拖拽所需的
mousedown事件,不需要每次进入编辑模式遍历重绑
修改后的完整JavaScript代码如下:
//Global variables let count = 1; let canvas = document.querySelector('#canvas'); let canvasContainer = document.querySelector('.canvas-container'); let designBtn = document.querySelector('#design-btn'); let editBtn = document.querySelector('#edit-btn'); let isDesign = false; let isEdit = false; let circleArray = []; // 拖拽相关全局变量 let mouseDown = false; let offset = []; let circleClickedOn = []; designBtn.addEventListener('click', (event)=>{ isDesign = true; isEdit = false; designBtn.style.backgroundColor = '#BA4A00' designBtn.style.color = '#17202A' editBtn.style.backgroundColor = null; editBtn.style.color = null }) editBtn.addEventListener('click', (event)=>{ isDesign = false; isEdit = true; editBtn.style.backgroundColor = '#BA4A00' editBtn.style.color = '#17202A' designBtn.style.backgroundColor = null; designBtn.style.color = null }) function create_circle_element(x, y){ let circle = document.createElement('div') const circleHeight = 40; const circleWidth = 40; circle.style.position = 'absolute'; circle.style.backgroundColor = 'orange'; circle.style.height = `${circleHeight}px`; circle.style.width = `${circleWidth}px`; circle.style.borderRadius = '50%' circle.style.textAlign = 'center'; circle.style.lineHeight = `${circleHeight}px`; circle.style.cursor = 'pointer'; circle.style.left = `${(x - (canvas.offsetLeft + canvasContainer.offsetLeft - window.scrollX)) - (circleWidth/2)}px`; circle.style.top = `${(y -(canvas.offsetTop + canvasContainer.offsetTop - window.scrollY)) - (circleHeight/2)}px` circle.textContent = `${count}`; canvas.append(circle) circleArray.push(circle) count++ // 新建圆形时直接绑定拖拽触发事件,仅绑定一次 circle.addEventListener('mousedown', (event)=>{ if(!isEdit) return mouseDown = true; offset = [ circle.offsetLeft - event.clientX, circle.offsetTop - event.clientY ] circleClickedOn = [circle] }) } // 初始化绑定设计模式的点击添加事件,仅绑定一次 canvas.addEventListener('mousedown', (event)=>{ if(!isDesign) return const mousePosition = { x: event.clientX, y: event.clientY } create_circle_element(mousePosition.x, mousePosition.y); }) // 初始化绑定编辑模式的相关事件,仅绑定一次 canvas.addEventListener('mouseup', ()=>{ mouseDown = false }) canvas.addEventListener('mousemove', (event)=>{ if(!isEdit || !mouseDown || !circleClickedOn[0]) return const mousePosition = { x: event.clientX, y: event.clientY } circleClickedOn[0].style.left = `${offset[0] + mousePosition.x}px` circleClickedOn[0].style.top = `${offset[1] + mousePosition.y}px` })
内容的提问来源于stack exchange,提问作者tim_woods
相关产品推荐
相关产品推荐

