You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript单次点击添加两次Div元素问题排查与解决

问题产生原因
  • 核心触发点:每次点击设计按钮调用begin_design函数时,都会给canvas元素新增一个mousedown事件监听器,多次切换设计/编辑模式就会重复绑定多组相同的监听。触发点击时所有绑定的监听函数都会执行,所以切换编辑后再回设计模式,单次点击会同时生成2个圆形,切换次数越多生成的圆形数量也会同步增加。
  • 附带隐患:edit_design函数同样存在重复绑定问题,每次点击编辑按钮都会给canvas重复绑定mouseup、mousemove事件,给所有已生成的圆形重复绑定mousedown事件,会导致拖拽逻辑多次执行、出现卡顿或拖拽异常。
修复方案

推荐采用「全局事件单次绑定+状态变量控制逻辑执行」的方案,不需要反复绑定/解绑事件,改造成本低、稳定性高:

  1. 移除按钮点击事件中对begin_design、edit_design的调用,按钮点击只负责切换状态和样式
  2. 所有事件监听只在页面初始化时绑定一次,通过isDesign、isEdit变量控制对应逻辑是否生效
  3. 新建圆形时直接绑定拖拽所需的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 23:48:03