JavaScript - 一次单击两次追加的 Div 元素

Posted

技术标签:

【中文标题】JavaScript - 一次单击两次追加的 Div 元素【英文标题】:JavaScript - Div Elements Appending Twice on One Click 【发布时间】:2021-12-06 20:25:03 【问题描述】:

//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 offset = [];


//Click event listener for design button
designBtn.addEventListener('click', (event)=>
  isDesign = true;
  isEdit = false;

  designBtn.style.backgroundColor = '#BA4A00'
  designBtn.style.color = '#17202A'

  editBtn.style.backgroundColor = null;
  editBtn.style.color = null

  //Invoke being_design function
  begin_design()
)

//Click event listener for edit button
editBtn.addEventListener('click', (event)=>
  isDesign = false;
  isEdit = true;

  editBtn.style.backgroundColor = '#BA4A00'
  editBtn.style.color = '#17202A'

  designBtn.style.backgroundColor = null;
  designBtn.style.color = null

  //Invoke edit_design function
  edit_design()
)



//Function creates new element and then appends it to the parent div
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 = `$circleHeightpx`;
  circle.style.width = `$circleWidthpx`;
  circle.style.borderRadius = '50%'
  circle.style.textAlign = 'center';
  circle.style.lineHeight = `$circleHeightpx`;
  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++



//Function responsible for adding circles to the canvas
//Function is invoked when design button is clicked
function begin_design()
    let mousePosition;
    canvas.addEventListener('mousedown', (event)=>
    if(isDesign)
      mousePosition = 
        x: event.clientX,
        y: event.clientY
      
        create_circle_element(mousePosition.x, mousePosition.y);
      
    )



//Function responsible for editing the circles on the canvas i.e moving them around on mousedown/mousemove event
//Function is invoked when edit button is clicked
function edit_design()
  if(isEdit)
  let mouseDown = false;
  let offset = [];
  let circleClickedOn = [];

//Set mouseDown to false
  canvas.addEventListener('mouseup', ()=>
    mouseDown = false
  )

//Loop through the newly created circles and attached 'mousedown' event to each
  circleArray.forEach((circleElement)=>
    circleElement.addEventListener('mousedown', (event)=>

      mouseDown = true;
      offset = [
        circleElement.offsetLeft - event.clientX,
        circleElement.offsetTop - event.clientY
      ]
      circleClickedOn = [circleElement]
    )
  )

//Move circles around
  canvas.addEventListener('mousemove', (event)=>
    if(mouseDown)
     let mousePosition;

     mousePosition = 
       x: event.clientX,
       y: event.clientY
     

     circleClickedOn[0].style.left = `$offset[0] + mousePosition.xpx`
     circleClickedOn[0].style.top = `$offset[1] + mousePosition.ypx`
    
  )

*
  margin: 0;
  padding: 0;
  box-sizing: border-box;


body
  position: relative;
  width: 100%;
  min-height: 100vh;



.sidebar
  position: fixed;
  top: 0;
  left: 0;
  background-color: #17202A;
  width: 50px;
  min-height: 100vh;


.sidebar .sidebar-top
  position: relative;
  height: 35px;

.sidebar .sidebar-top #toggle-btn
  position: absolute;
  display: flex;
  height: 35px;
  width: 100%;
  justify-content: center;
  align-items: center;
  font-size: 18px;
  cursor: pointer;
  color: #808B96


.sidebar .sidebar-center
  position: relative;
  width: 100%;
  margin-top: 15px;

.sidebar .sidebar-center ul li
  position: relative;
  height: 35px;
  margin-bottom: 5px;
  list-style: none;

.sidebar .sidebar-center ul li a
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
  height: 35px;
  text-decoration: none


.sidebar .sidebar-center ul li a
  font-size: 18px;
  color: #808B96

.sidebar .sidebar-center ul li a:hover
  background-color: #2e4053



.canvas-container
  position: absolute;
  top: 0;
  width: calc(100% - 50px);
  min-height: 100vh;
  left: 50px;
  padding: 20px;
  background-color: #2E4053


.canvas-container #canvas
  position: relative;
  width: 100%;
  min-height: 100vh;
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
  <meta charset="utf-8">
  <title>testing</title>
  <link rel="stylesheet" href="style.css">
  <!-- Boxicons CDN Link -->
  <link href='https://unpkg.com/boxicons@2.0.7/css/boxicons.min.css' rel='stylesheet'>
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
  <body>
    <div class="sidebar">
      <div class="sidebar-top">
        <i class='bx bx-menu' id="toggle-btn"></i>
      </div>
      <div class="sidebar-center">
        <ul class="nav-list">
          <li>
            <a href="#" id="design-btn">
                <i class='bx bx-pyramid'></i>
            </a>
          </li>

          <li>
            <a href="#" id="edit-btn">
                <i class='bx bxs-edit-alt'></i>
            </a>
          </li>
        </ul>

      </div>
    </div>
    <div class="canvas-container">
      <div id="canvas"></div>
    <script src="script.js"></script>
  </body>
</html>

目标 - 当用户点击设计按钮时,圆圈会在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 offset = []


//Click event listener for design button
designBtn.addEventListener('click', (event)=>
  isDesign = true;
  isEdit = false;

  designBtn.style.backgroundColor = '#BA4A00'
  designBtn.style.color = '#17202A'

  editBtn.style.backgroundColor = null;
  editBtn.style.color = null

  //Invoke being_design function
  begin_design()
)

//Click event listener for edit button
editBtn.addEventListener('click', (event)=>
  isDesign = false;
  isEdit = true;

  editBtn.style.backgroundColor = '#BA4A00'
  editBtn.style.color = '#17202A'

  designBtn.style.backgroundColor = null;
  designBtn.style.color = null

  //Invoke edit_design function
  edit_design()
)



//Function creates new element and then appends it to the parent div
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 = `$circleHeightpx`;
  circle.style.width = `$circleWidthpx`;
  circle.style.borderRadius = '50%'
  circle.style.textAlign = 'center';
  circle.style.lineHeight = `$circleHeightpx`;
  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++



//Function responsible for adding circles to the canvas
//Function is invoked when design button is clicked
function begin_design()
    let mousePosition;
    canvas.addEventListener('mousedown', (event)=>
    if(isDesign)
      mousePosition = 
        x: event.clientX,
        y: event.clientY
      
        create_circle_element(mousePosition.x, mousePosition.y)
      
    )



//Function responsible for editing the circles on the canvas i.e moving them around on mousedown/mousemove event
//Function is invoked when edit button is clicked
function edit_design()
  if(isEdit)
  let mouseDown = false;
  let offset = [];
  let circleClickedOn = [];

//Set mouseDown to false
  canvas.addEventListener('mouseup', ()=>
    mouseDown = false
  )

//Loop through the newly created circles and attached 'mousedown' event to each
  circleArray.forEach((circleElement)=>
    circleElement.addEventListener('mousedown', (event)=>

      mouseDown = true;
      offset = [
        circleElement.offsetLeft - event.clientX,
        circleElement.offsetTop - event.clientY
      ]
      circleClickedOn = [circleElement]
    )
  )

//Move circles around
  canvas.addEventListener('mousemove', (event)=>
    if(mouseDown)
     let mousePosition;

     mousePosition = 
       x: event.clientX,
       y: event.clientY
     

     circleClickedOn[0].style.left = `$offset[0] + mousePosition.xpx`
     circleClickedOn[0].style.top = `$offset[1] + mousePosition.ypx`
    
  )


***HTML***
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
  <meta charset="utf-8">
  <title>Testing</title>
  <link rel="stylesheet" href="style.css">
  <!-- Boxicons CDN Link -->
  <link href='https://unpkg.com/boxicons@2.0.7/css/boxicons.min.css' rel='stylesheet'>
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
  <body>
    <div class="sidebar">
      <div class="sidebar-top">
        <i class='bx bx-menu' id="toggle-btn"></i>
      </div>
      <div class="sidebar-center">
        <ul class="nav-list">
          <li>
            <a href="#" id="design-btn">
                <i class='bx bx-pyramid'></i>
            </a>
          </li>

          <li>
            <a href="#" id="edit-btn">
                <i class='bx bxs-edit-alt'></i>
            </a>
          </li>
        </ul>

      </div>
    </div>
    <div class="canvas-container">
      <div id="canvas"></div>
    <script src="script.js"></script>
  </body>
</html>
***CSS***
*
  margin: 0;
  padding: 0;
  box-sizing: border-box;


body
  position: relative;
  width: 100%;
  min-height: 100vh;



.sidebar
  position: fixed;
  top: 0;
  left: 0;
  background-color: #17202A;
  width: 50px;
  min-height: 100vh;


.sidebar .sidebar-top
  position: relative;
  height: 35px;

.sidebar .sidebar-top #toggle-btn
  position: absolute;
  display: flex;
  height: 35px;
  width: 100%;
  justify-content: center;
  align-items: center;
  font-size: 18px;
  cursor: pointer;
  color: #808B96


.sidebar .sidebar-center
  position: relative;
  width: 100%;
  margin-top: 15px;

.sidebar .sidebar-center ul li
  position: relative;
  height: 35px;
  margin-bottom: 5px;
  list-style: none;

.sidebar .sidebar-center ul li a
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
  height: 35px;
  text-decoration: none


.sidebar .sidebar-center ul li a
  font-size: 18px;
  color: #808B96

.sidebar .sidebar-center ul li a:hover
  background-color: #2e4053



.canvas-container
  position: absolute;
  top: 0;
  width: calc(100% - 50px);
  min-height: 100vh;
  left: 50px;
  padding: 20px;
  background-color: #2E4053


.canvas-container #canvas
  position: relative;
  width: 100%;
  min-height: 100vh;


【问题讨论】:

此外,每次单击按钮时您都会添加额外的事件侦听器,但您永远不会删除之前的事件侦听器。 您好,我继续在帖子中添加了 sn-p。谢谢 @CherryDT,你说的是什么事件监听器? mousedown 和 mouseup 我明白了。它们究竟应该在哪里移除?我不能在每个按钮的点击事件中删除它,因为这会阻止它添加圆圈。 【参考方案1】:
    问题是每次用户切换到设计模式时,您都会在设计模式下注册鼠标按下事件处理程序。 但是您永远不会在切换到编辑模式时取消注册鼠标按下事件处理程序。 这会导致为画布单击事件(鼠标按下)注册多个事件处理程序。 因此,每当您切换回设计模式并单击画布时,它都会为先前注册的侦听器和新注册的侦听器触发单击处理程序。 检查更新的 sn-p

注释行标有// 解决方法:

//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 offset = [];


//Click event listener for design button
designBtn.addEventListener('click', (event)=>
  isDesign = true;
  isEdit = false;

  designBtn.style.backgroundColor = '#BA4A00'
  designBtn.style.color = '#17202A'

  editBtn.style.backgroundColor = null;
  editBtn.style.color = null

  //Invoke being_design function
  begin_design()
)

//Click event listener for edit button
editBtn.addEventListener('click', (event)=>
  isDesign = false;
  isEdit = true;

  editBtn.style.backgroundColor = '#BA4A00'
  editBtn.style.color = '#17202A'

  designBtn.style.backgroundColor = null;
  designBtn.style.color = null

  //Invoke edit_design function
  edit_design()
)



//Function creates new element and then appends it to the parent div
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 = `$circleHeightpx`;
  circle.style.width = `$circleWidthpx`;
  circle.style.borderRadius = '50%'
  circle.style.textAlign = 'center';
  circle.style.lineHeight = `$circleHeightpx`;
  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++


// Solution : Define a click handler
var designClickHandler = (event)=>
    if(isDesign)
      mousePosition = 
        x: event.clientX,
        y: event.clientY
      
        create_circle_element(mousePosition.x, mousePosition.y);
      
    

//Function responsible for adding circles to the canvas
//Function is invoked when design button is clicked
function begin_design()
    let mousePosition;
    
    // Solution : Register click handler
    canvas.addEventListener('mousedown', designClickHandler)



//Function responsible for editing the circles on the canvas i.e moving them around on mousedown/mousemove event
//Function is invoked when edit button is clicked
function edit_design()
  if(isEdit)
  
  // Solution : unregister click handler
  canvas.removeEventListener('mousedown', designClickHandler)

  
  let mouseDown = false;
  let offset = [];
  let circleClickedOn = [];

//Set mouseDown to false
  canvas.addEventListener('mouseup', ()=>
    mouseDown = false
  )

//Loop through the newly created circles and attached 'mousedown' event to each
  circleArray.forEach((circleElement)=>
    circleElement.addEventListener('mousedown', (event)=>

      mouseDown = true;
      offset = [
        circleElement.offsetLeft - event.clientX,
        circleElement.offsetTop - event.clientY
      ]
      circleClickedOn = [circleElement]
    )
  )

//Move circles around
  canvas.addEventListener('mousemove', (event)=>
    if(mouseDown)
     let mousePosition;

     mousePosition = 
       x: event.clientX,
       y: event.clientY
     

     circleClickedOn[0].style.left = `$offset[0] + mousePosition.xpx`
     circleClickedOn[0].style.top = `$offset[1] + mousePosition.ypx`
    
  )

*
  margin: 0;
  padding: 0;
  box-sizing: border-box;


body
  position: relative;
  width: 100%;
  min-height: 100vh;
  user-select: none;



.sidebar
  position: fixed;
  top: 0;
  left: 0;
  background-color: #17202A;
  width: 50px;
  min-height: 100vh;


.sidebar .sidebar-top
  position: relative;
  height: 35px;

.sidebar .sidebar-top #toggle-btn
  position: absolute;
  display: flex;
  height: 35px;
  width: 100%;
  justify-content: center;
  align-items: center;
  font-size: 18px;
  cursor: pointer;
  color: #808B96


.sidebar .sidebar-center
  position: relative;
  width: 100%;
  margin-top: 15px;

.sidebar .sidebar-center ul li
  position: relative;
  height: 35px;
  margin-bottom: 5px;
  list-style: none;

.sidebar .sidebar-center ul li a
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
  height: 35px;
  text-decoration: none


.sidebar .sidebar-center ul li a
  font-size: 18px;
  color: #808B96

.sidebar .sidebar-center ul li a:hover
  background-color: #2e4053



.canvas-container
  position: absolute;
  top: 0;
  width: calc(100% - 50px);
  min-height: 100vh;
  left: 50px;
  padding: 20px;
  background-color: #2E4053


.canvas-container #canvas
  position: relative;
  width: 100%;
  min-height: 100vh;
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
  <meta charset="utf-8">
  <title>hiveport</title>
  <link rel="stylesheet" href="style.css">
  <!-- Boxicons CDN Link -->
  <link href='https://unpkg.com/boxicons@2.0.7/css/boxicons.min.css' rel='stylesheet'>
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
  <body>
    <div class="sidebar">
      <div class="sidebar-top">
        <i class='bx bx-menu' id="toggle-btn"></i>
      </div>
      <div class="sidebar-center">
        <ul class="nav-list">
          <li>
            <a href="#" id="design-btn">
                <i class='bx bx-pyramid'></i>
            </a>
          </li>

          <li>
            <a href="#" id="edit-btn">
                <i class='bx bxs-edit-alt'></i>
            </a>
          </li>
        </ul>

      </div>
    </div>
    <div class="canvas-container">
      <div id="canvas"></div>
    <script src="script.js"></script>
  </body>
</html>

【讨论】:

是的,做到了。非常感谢! 9小时后奖励+50赏金。谢谢

以上是关于JavaScript - 一次单击两次追加的 Div 元素的主要内容,如果未能解决你的问题,请参考以下文章

两次尝试后触发Javascript

请问JMeter能不能比较两次测试运行的结果,是否不能测试JavaScript?

tap点击一次,内部程序执行两次,多次

如何避免重复请求按钮单击两次

如何防止用户单击按钮两次?

VueJs:按钮单击仅在单击两次时有效