简体   繁体   中英

Disable an on click event after the first click

I have a function that counts every time a user clicks on and image on the page:

for(var i = 0; i < document.getElementsByClassName("face").length; i++){
    document.getElementsByClassName("face")[i].addEventListener("click", counter)
}

function counter(){
    count ++;
}

And I want to disable it after the first click so it won't keep counting duplicate clicks of the same picture. I know adding this.onclick=null on the HTML tag will work, but I'm wondering if there a way to do this on the javascript file itself so I don't need to put javascript onto my HTML file.

You need to remove event listener from each clicked element:

function counter(){
    count++;
    this.removeEventListener('click', counter);
}

If you don't want to remove the event (in case you need it reactivated again later or something), you can make count an array of booleans, and each button will flip the value of its own index. No duplicates that way and you would still be able to easily get the sum of all true flags.

var count = [];
function counter(i){
    count[i] = true;
}

Quick live example:

 var count = []; var faces = document.getElementsByClassName("face"); var result = document.getElementById('t'); for(var i = 0; i < faces.length; i++){ handle(i); } function counter(i){ var total = 0; count[i] = true; count.concat([]).reduce(function(p, c){c ? total++ : ''}, 0); result.textContent = total; } function handle(i){ faces[i].addEventListener("click", function(){ counter(i); this.className = 'face clicked'; }) }
 button {width: 50px; height: 50px} button.clicked {opacity: 0.2}
 <button class="face"></button> <button class="face"></button> <button class="face"></button> <button class="face"></button> <p>Count: <span id="t">0</span></p>

There is a neater way to handle the functionality you seek. I think what you want is a list of the images that have been clicked like @Shomz thinks as well. Is that correct?

1) The length property of the for loop is evaluated each iteration in the loop. Fetching the element from the DOM again with the index i on each iteration is slow.

for(var i = 0; i < document.getElementsByClassName("face").length; i++){
    document.getElementsByClassName("face")[i].addEventListener("click", counter)
}

An improvement is to change it into this:

var faces = document.getElementsByClassName("face");
for (var i = 0, var len = faces.length; i < len; i++) {
    faces[i].addEventListener("click", counter)
}

2) But the code still attach an event listener to every single image. This is slow if you have many images. A better way is to let click events bubble upwards and catch them at a parent level. This is called event delegation . This way you don't need a loop, and merely a single event handler needs to be attached.

I store the id of the image, but you could store whatever you need from the node of course that is unique (the src?).

var clickedFaces = [];

document.getElementById('ImageContainer').addEventListener("click", onFaceClick);

function onFaceClick(e) {
    if (e.target.className === 'face' && clickedFaces.indexOf(e.target.id) !== -1) {
        clickedFaces.push(e.target.id);
    }
}

If you want to know how many faces have been clicked:

console.log(clickedFaces.length);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM