javascript html dom-events

javascript - ¿Cómo hacer que la función onclick se ejecute solo una vez?



html dom-events (7)

Tengo este código para Google Analytics en un botón. Necesito que se ejecute solo una vez, para que el usuario no pueda cambiar las estadísticas presionando el botón muchas veces. Intenté soluciones de temas similares, pero no funcionan. Por favor ayuda. Este es mi codigo.

<script> function klikaj(i) { gtag(''event'', ''first-4'', { ''event_category'' : ''cat-4'', ''event_label'' : ''site'' }); } document.body.addEventListener("click", klikaj(i), {once:true}) </script> <div id="thumb0" class="thumbs" onclick="klikaj(''rad1'')">My button</div>


Manejadores de eventos y oyentes

Hay tres formas * de registrar un evento en un elemento. Los siguientes ejemplos muestran cómo registrar el evento click en un enlace con la clase .once ** que llama a la función test() cuando se activa.

  1. Oyente de eventos (recomendado)
    • document.querySelector(''.once'') .addEventListener (''clic'', prueba); ``
  2. Atributo en evento ( no recomendado)
    • <a href=''#/'' class=''once'' onclick=''test()''> >Click</a>
  3. Propiedad en el evento
    • document.querySelector(''.once'') .onclick = prueba; ``

* Consulte los controladores DOM en el evento para más detalles
**. Una .once clase no es relevante para # 2

Cuestiones

El OP ( O riginal P ost) tiene un detector de eventos (ver # 1 arriba) registrando un evento click en la etiqueta <body> y un atributo en el evento (ver # 2 arriba) registrando el evento click en un <div> . Cada uno llama a una función (también conocida como función de devolución de llamada) llamada klikaj() que es redundante. Hacer clic en el cuerpo (que normalmente está en todas partes) no es útil cuando pretendes que el usuario haga clic en un div. Si el usuario hace clic en cualquier lugar que no sea div , se klikaj() . Si el usuario hace clic en el div, se klikaj() dos veces. Sugiero que elimine ambos controladores de eventos y los reemplace con esto:

A.

document.getElementById(''thumb0'').addEventListener("click", klikaj);

Tenga en cuenta que klikaj no tiene paréntesis () porque el navegador interpreta () como ejecutar la función ahora en lugar de cuando el usuario desencadena el evento registrado (ver # 1 y # 3 arriba). Si un controlador de eventos tiene sentencias adicionales y / o funciones de devolución de llamada, se debe incluir una función anónima y se aplica la sintaxis normal:

SEGUNDO.

document.getElementById(''thumb0'').addEventListener("click", function(event) { klikaj(); console.log(''clicked''); });

Una alternativa más limpia es agregar líneas adicionales en la definición de la función de devolución de llamada y registrar eventos como #A.

Solución

Simplemente agregue la siguiente declaración como la última línea de klikaj() :

this.style.pointerEvents = "none";

Eso hará que la etiqueta cliqueada no se pueda hacer clic. Aplicado al código OP, debería ser así:

<div id="thumb0" class="thumbs">Thumb 0</div> <script> function klikaj(event) { gtag(''event'', ''first-4'', { ''event_category'' : ''cat-4'', ''event_label'' : ''site'' }); this.style.pointerEvents = "none"; } document.getElementById(''thumb0'').addEventListener("click", klikaj); </script>

Manifestación

La siguiente demostración tiene dos enlaces:

  1. .default : un enlace normal registrado en el evento de clic que, cuando se activa, test() llamadas test()

  2. .once : un enlace registrado en el evento click que, cuando se activa, llama a test() y hace que el enlace no se pueda hacer clic.

function test() { console.log(''test''); } document.querySelector(''.default'').onclick = function(e) { test(); } document.querySelector(''.once'').onclick = function(e) { test(); this.style.pointerEvents = ''none''; }

<a href=''#/'' class=''default''>Default</a><br> <a href=''#/'' class=''once''>Once</a>


Elimine el atributo onclick en su botón y registre el oyente a través de JavaScript, como intentó hacer:

<div id="thumb0" class="thumbs" style="border: 1px solid; cursor: pointer; float: left"> My button </div> <script> function klikaj(i) { console.log(i); } document.getElementById(''thumb0'') .addEventListener("click", function(event) { klikaj(''rad1''); }, {once: true}); </script>

Si su navegador no admite la opción { once: true } , puede eliminar el detector de eventos manualmente:

<div id="thumb0" class="thumbs" style="border: 1px solid;cursor: pointer;float:left"> My button </div> <script> function klikaj(i) { console.log(i); } function onClick(event) { klikaj(''rad1''); document .getElementById(''thumb0'') .removeEventListener("click", onClick); } document .getElementById(''thumb0'') .addEventListener("click", onClick); </script>


Hay un problema con la forma en que intenta adjuntar la función del controlador. La función klikaj(i) regresa undefined por lo que está adjuntando indefinida al botón. Si desea ejecutar klikaj(i) cuando se hace clic en el botón, klikaj(i) dentro de un cierre como este:

const button = document.querySelector(''button'') const i = 10 function klikaj(i) {console.log(''clicked once'')} button.addEventListener(''click'', () => { klikaj(i) }, {once: true})

<button>Hello world</button>

Si el navegador no admite {once: true} , puede simularlo usando:

const button = document.querySelector(''button'') const i = 10 function klikaj(i) {console.log("clicked once")} function clickOnceHandler(event) { klikaj(i) event.currentTarget.removeEventListener(''click'', clickOnceHandler) } button.addEventListener(''click'', clickOnceHandler)

<button>Hello world</button>


Recomendaría establecer una variable y verificar su valor.

<script> var clicked = false; function klikaj(i) { if (clicked === false) { gtag(''event'', ''first-4'', { ''event_category'' : ''cat-4'', ''event_label'' : ''site'' }); } clicked = true; } ... </script>

O eliminar el evento onclick según lo sugerido por otros,

<script> function klikaj(i) { gtag(''event'', ''first-4'', { ''event_category'' : ''cat-4'', ''event_label'' : ''site'' }); document.getElementById(''thumb0).onclick = undefined; } ... </script>

Tenga en cuenta que, once: true desafortunadamente no es compatible con IE y Edge. Ver MDN


Si desea que se invoque la función solo cuando el usuario hace clic en el botón, deberá eliminar el detector de eventos de clic del cuerpo.

Para activar su función gtag solo una vez, puede cambiar la definición de la función de klikaj dentro del cuerpo de la función. Después de la primera llamada, nunca se llamará a gtag.

El siguiente código funciona bien.

<script> function klikaj(i) { gtag(''event'', ''first-4'', { ''event_category'' : ''cat-4'', ''event_label'' : ''site'' }); klikaj = function() {}; } </script> <div id="thumb0" class="thumbs" onclick="klikaj(''rad1'')"> My button </div>


Simplemente use una variable de bandera y configúrela en la primera ejecución:

var handlerExecuted = false; function clickHandler() { if (!handlerExecuted) { console.log("call gtag() here"); handlerExecuted = true; } else { console.log("not calling gtag() function"); } } document .getElementById("thumb0") .addEventListener("click", clickHandler);

<div id="thumb0" class="thumbs">My button</div>

Una variación avanzada que usa cierres y podría usarse en varios botones:

function clickHandlerFactory() { var handlerExecuted = false; return function() { if (!handlerExecuted) { console.log("call gtag() here"); handlerExecuted = true; } else { console.log("not calling gtag() function"); } } } [...document.querySelectorAll(".thumbs")].forEach(function(el) { el.addEventListener("click", clickHandlerFactory()); });

<div id="thumb0" class="thumbs">Button 1</div> <div id="thumb1" class="thumbs">Button 2</div>


puede usar removeAttribute() esta manera: document.getElementById(''thumb0'').removeAttribute("onclick");

o puede dejar que la función devuelva falso de esta manera: document.getElementById(''thumb0'').onclick = ()=> false