最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - addEventListener('click', function(), {once: true}) firing multiple times in the same position - St

programmeradmin0浏览0评论

let doorLeft = document.getElementById("left");
let doorMiddle = document.getElementById("middle");
let doorRight = document.getElementById("right");
let resetButton = document.getElementById("reset");

let numberOfClicks = 0;

function incrementClicks() {
  numberOfClicks++;
  console.log('Number of clicks: ' + numberOfClicks)
}
/* -------------------------------------------------------------------------- */
/*                         handle click door only once                        */
/* -------------------------------------------------------------------------- */
const revealDoorColour = () => {
  doorLeft.addEventListener(
    "click",
    () => {
      incrementClicks();
    }, {
      once: true,
    }
  );
  doorMiddle.addEventListener(
    "click",
    () => {
      incrementClicks();
    }, {
      once: true,
    }
  );
  doorRight.addEventListener(
    "click",
    () => {
      incrementClicks();
    }, {
      once: true,
    }
  );
};

/* -------------------------------------------------------------------------- */

const reset = () => {
  doorLeft.style.backgroundColor = "paleturquoise";
  doorRight.style.backgroundColor = "paleturquoise";
  doorMiddle.style.backgroundColor = "paleturquoise";
  revealDoorColour();
  resetButton.innerHTML = "Let's play";
};

resetButton.addEventListener("click", function() {
  reset();
  numberOfClicks = 0;
});
.container.main {
  display: flex;
  justify-content: space-around;
  padding: 0 20%;
}

.door {
  height: 500px;
  width: 300px;
  margin: 10px;
}

#left {
  background-color: paleturquoise;
}

#middle {
  background-color: paleturquoise;
}

#right {
  background-color: paleturquoise;
}

.score {
  text-align: center;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> -->
  <title>Door guesser</title>
  <script src="./js/main.js" async></script>
  <link rel="stylesheet" href="./css/style.css">
</head>

<body>

  <div class="container main">
    <div class="door" id="left">

    </div>

    <div class="door" id="middle">

    </div>

    <div class="door" id="right">

    </div>

  </div>

  <div class="container score">
    <div class="currentScoreGroup">
      <div>Current score: </div>
      <div id="currentScore">0</div>
    </div>

    <div class="bestScoreGroup">
      <div>Best score: </div>
      <div id="bestScore">0</div>
    </div>

    <button class="reset" id='reset'>Let's play </button>
  </div>

</body>

</html>

let doorLeft = document.getElementById("left");
let doorMiddle = document.getElementById("middle");
let doorRight = document.getElementById("right");
let resetButton = document.getElementById("reset");

let numberOfClicks = 0;

function incrementClicks() {
  numberOfClicks++;
  console.log('Number of clicks: ' + numberOfClicks)
}
/* -------------------------------------------------------------------------- */
/*                         handle click door only once                        */
/* -------------------------------------------------------------------------- */
const revealDoorColour = () => {
  doorLeft.addEventListener(
    "click",
    () => {
      incrementClicks();
    }, {
      once: true,
    }
  );
  doorMiddle.addEventListener(
    "click",
    () => {
      incrementClicks();
    }, {
      once: true,
    }
  );
  doorRight.addEventListener(
    "click",
    () => {
      incrementClicks();
    }, {
      once: true,
    }
  );
};

/* -------------------------------------------------------------------------- */

const reset = () => {
  doorLeft.style.backgroundColor = "paleturquoise";
  doorRight.style.backgroundColor = "paleturquoise";
  doorMiddle.style.backgroundColor = "paleturquoise";
  revealDoorColour();
  resetButton.innerHTML = "Let's play";
};

resetButton.addEventListener("click", function() {
  reset();
  numberOfClicks = 0;
});
.container.main {
  display: flex;
  justify-content: space-around;
  padding: 0 20%;
}

.door {
  height: 500px;
  width: 300px;
  margin: 10px;
}

#left {
  background-color: paleturquoise;
}

#middle {
  background-color: paleturquoise;
}

#right {
  background-color: paleturquoise;
}

.score {
  text-align: center;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> -->
  <title>Door guesser</title>
  <script src="./js/main.js" async></script>
  <link rel="stylesheet" href="./css/style.css">
</head>

<body>

  <div class="container main">
    <div class="door" id="left">

    </div>

    <div class="door" id="middle">

    </div>

    <div class="door" id="right">

    </div>

  </div>

  <div class="container score">
    <div class="currentScoreGroup">
      <div>Current score: </div>
      <div id="currentScore">0</div>
    </div>

    <div class="bestScoreGroup">
      <div>Best score: </div>
      <div id="bestScore">0</div>
    </div>

    <button class="reset" id='reset'>Let's play </button>
  </div>

</body>

</html>

Following Extract function from addEventListener I've added the {once:true} parameter which seems to work fine most of the time. However, when clicking on the div in question, it randomly gets fired multiple times (at the same x/y coordinates). How is this possible? I set a breakpoint in the anonymous function and it runs through it multiple times. Any ideas?

To replicate the issue

  1. Click Let's play
  2. Click any card
  3. click Let's play once again
  4. Click a different card
  5. Now you should see 2 entries (clicks) in the console

Share Improve this question edited May 25, 2021 at 22:01 Brian Tompsett - 汤莱恩 5,89372 gold badges61 silver badges133 bronze badges asked May 25, 2021 at 15:32 gabegabe 952 silver badges8 bronze badges 5
  • 2 Hi! Please update your question with a minimal reproducible example demonstrating the problem, ideally a runnable one using Stack Snippets (the [<>] toolbar button); here's how to do one. Perhaps these elements are nested within one another? – T.J. Crowder Commented May 25, 2021 at 15:34
  • Done :) Sorry for the minimal info provided at first. – gabe Commented May 25, 2021 at 15:48
  • 1 Hi! I'm afraid you've gone the other way. Please do read through the link above for details. – T.J. Crowder Commented May 25, 2021 at 15:52
  • Oops. I think this is the bare minimum I can strip it to so it still misbehaves – gabe Commented May 25, 2021 at 16:13
  • If I click "Let's play" and then click Door 1, I get a message. If I clidk Door 1 again, I don't; I do if I click a different door, but that's a different handler entirely. That's what {once: true} does. What are you expecting intead? – T.J. Crowder Commented May 25, 2021 at 16:20
Add a ment  | 

1 Answer 1

Reset to default 5

The once option of addEventListener work like this:

once
    A Boolean indicating that the listener should be invoked at most once after being added.
    If true, the listener would be automatically removed when invoked.

So if a div is not clicked, its handler still stay there. When you click play again, you basically add more event listener to the div. What why it randomly gets fired multiple times (at the same x/y coordinates)

To fix that, just remove the event listener in reset

let doorLeft = document.getElementById("left");
let doorMiddle = document.getElementById("middle");
let doorRight = document.getElementById("right");
let resetButton = document.getElementById("reset");

let numberOfClicks = 0;

function incrementClicks() {
  numberOfClicks++;
  console.log('Number of clicks: ' + numberOfClicks)
}
/* -------------------------------------------------------------------------- */
/*                         handle click door only once                        */
/* -------------------------------------------------------------------------- */
const revealDoorColour = () => {
  doorLeft.removeEventListener("click", incrementClicks);
  doorMiddle.removeEventListener("click", incrementClicks);
  doorRight.removeEventListener("click", incrementClicks);
  //
  doorLeft.addEventListener("click", incrementClicks, { once: true });
  doorMiddle.addEventListener("click", incrementClicks, { once: true });
  doorRight.addEventListener("click", incrementClicks, { once: true });
};

/* -------------------------------------------------------------------------- */

const reset = () => {
  doorLeft.style.backgroundColor = "paleturquoise";
  doorRight.style.backgroundColor = "paleturquoise";
  doorMiddle.style.backgroundColor = "paleturquoise";
  revealDoorColour();
  resetButton.innerHTML = "Let's play";
};

resetButton.addEventListener("click", function() {
  reset();
  numberOfClicks = 0;
});
.container.main {
  display: flex;
  justify-content: space-around;
  padding: 0 20%;
}

.door {
  height: 500px;
  width: 300px;
  margin: 10px;
}

#left {
  background-color: paleturquoise;
}

#middle {
  background-color: paleturquoise;
}

#right {
  background-color: paleturquoise;
}

.score {
  text-align: center;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> -->
  <title>Door guesser</title>
  <script src="./js/main.js" async></script>
  <link rel="stylesheet" href="./css/style.css">
</head>

<body>

  <div class="container main">
    <div class="door" id="left">

    </div>

    <div class="door" id="middle">

    </div>

    <div class="door" id="right">

    </div>

  </div>

  <div class="container score">
    <div class="currentScoreGroup">
      <div>Current score: </div>
      <div id="currentScore">0</div>
    </div>

    <div class="bestScoreGroup">
      <div>Best score: </div>
      <div id="bestScore">0</div>
    </div>

    <button class="reset" id='reset'>Let's play </button>
  </div>

</body>

</html>

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论