En jQuery, ¿cómo puedo distinguir entre una programática y un clic de usuario?

91

Digamos que tengo un controlador de clic definido:

$("#foo").click(function(e){

});

¿Cómo puedo, dentro del controlador de funciones, saber si el evento fue activado mediante programación o por el usuario?

Kevin Owocki
fuente
¿Cómo realiza el programa la activación de un evento mediante programación?
Clayton
5
¿Por qué necesitas distinguir los casos?
Damien_The_Unbeliever
@Clayton: $x.click()o $x.trigger('click').
mu es demasiado corto
Tuve una situación con un control deslizante de imágenes que se desplazaba automáticamente a través de las imágenes y lo hice activando clics en el elemento de navegación correcto asociado con la imagen. El problema es que cuando el usuario hace clic en el navegador, la rotación automática debería detenerse.
Kasapo
2
Esto funciona en las últimas versiones de Firefox, Chrome e IE9. ¿Por qué no aceptar la respuesta a continuación con la mayor cantidad de votos? @kevino
OZZIE

Respuestas:

119

Podrías echar un vistazo al objeto de evento e. Si el evento se desencadena por una verdadera clic, usted tendrá cosas como clientX, clientY, pageX, pageY, etc. dentro ey serán números; Estos números están relacionados con la posición del mouse cuando se activa el clic, pero probablemente estarán presentes incluso si el clic se inició a través del teclado. Si el evento fue activado por, $x.click()entonces no tendrá los valores de posición habituales en e. También puede mirar la originalEventpropiedad , que no debería estar allí si el evento vino $x.click().

Quizás algo como esto:

$("#foo").click(function(e){
    if(e.hasOwnProperty('originalEvent'))
        // Probably a real click.
    else
        // Probably a fake click.
});

Y aquí hay una pequeña caja de arena para jugar: http://jsfiddle.net/UtzND/

mu es demasiado corto
fuente
4
Eso es asombroso ... ¡Solo pensé para mí mismo "tal vez los eventos activados por jQuery no tienen información de posición del mouse"! w00t!
Kasapo
2
Esto se puede evitar en los navegadores que admiten createEvent. jsfiddle.net/UtzND/26
Joe Enzminger
2
@JoeEnzminger sí, pero ¿por qué derrotarías tu propio guión, por así decirlo ...?
OZZIE
3
Me preocupa un script de terceros que genera un evento de clic y mi script lo maneja asumiendo que fue generado por el usuario (un clic real).
Joe Enzminger
2
@JoeEnzminger: Todas las apuestas se cancelan una vez que su código está en el navegador, no hay nada que pueda hacer que no pueda ser derrotado por una persona lo suficientemente inteligente. Creo que lo mejor que puedes hacer es comprobar un montón de cosas: ¿hay un originalEvent? ¿Es el tipo de cosas correcto? ¿Hay coordenadas en alguna parte? ¿Son coherentes las coordenadas? ¿Están las coordenadas adentro #foo? ...
mu es demasiado corto
44

Puede utilizar un parámetro adicional como se indica en el manual de activación de jQuery :

$("#foo").click(function(e, from){
    if (from == null)
        from = 'User';
    // rest of your code
});

$('#foo').trigger('click', ['Trigger']);
Shikiryu
fuente
3
El único problema que veo con esto es que no se puede distinguir entre un clic normal y $x.click()la .click()persona que llama tiene que decirle explícitamente que está fingiendo. Esto puede o no ser un problema dependiendo de lo que esté haciendo Kevin Owocki.
mu es demasiado corto
1
@mu: No entiendo bien la diferencia entre un clic "normal" (¿usuario?) y $x.click()cuál es el manejador de eventos (para el clic del usuario, que puede ser "normal")
Shikiryu
1
La diferencia es que uno proviene del usuario y el otro del software. El clic falso puede provenir de un complemento o de algún otro código que no se puede modificar para agregar argumentos adicionales. No estoy criticando su solución, solo señalando algunos posibles agujeros.
mu es demasiado corto
Aunque mu es correcta y esto no funcionará en todas las situaciones, era exactamente lo que estaba buscando, ¡gracias! No sabía que podía pasar el parámetro adicional como una var, pero eso es exactamente lo que necesitaba para probar los clics "reales" en una interfaz de usuario complicada que trata algunos clics "reales" como programáticos. ¡Gracias por ambas soluciones increíblemente útiles!
Phil
9

Ya hay otra pregunta respondida.

¿Cómo detectar si un clic () es un clic del mouse o se activa por algún código?

Utilice la whichpropiedad del objeto de evento. Debería ser undefinedpara eventos activados por código

$("#someElem").click(function(e) {
    if (e.which) {
        // Actually clicked
    } else {
        // Triggered by code
    }
});

Ejemplo de JsFiddle - http://jsfiddle.net/interdream/frw8j/

¡Espero eso ayude!

Swanidhi
fuente
2
No siempre funciona. Por ejemplo select, daría un e.which==undefinedpar por un evento genuino.
JNF
5

He probado todas las soluciones anteriores, pero en mi caso no ha funcionado nada. La siguiente solución funcionó para mí. Espero que también te ayude.

$(document).ready(function(){
  //calling click event programmatically
    $("#chk1").trigger("click");
});

$(document).on('click','input[type=checkbox]',function(e) {
		if(e.originalEvent.isTrusted==true){
			alert("human click");
		}
		else{
			alert("programmatically click");
		}
    
    });
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.3.1.min.js">
</script>

<input type="checkbox" id="chk1" name="chk1" >Chk1</input>
<input type="checkbox" id="chk2" name="chk2" >Chk2</input>
<input type="checkbox" id="chk3" name="chk3" >Chk3</input>

GSB
fuente
4

DOM Nivel 3 especifica event.isTrusted. Esto solo se admite actualmente en IE9 + y Firefox (según mis pruebas. También he leído (aunque no he investigado a fondo) que se puede anular en algunos navegadores y probablemente aún no esté 100% listo para ser realmente confiable (desafortunadamente).

Esta es una versión modificada del violín de @ mu que funciona en IE y Firefox.

Joe Enzminger
fuente
Buen punto. Sin embargo, no creo que nada vaya a ser 100% sólido. Tendría que mezclar algunas pruebas para ver si isTrustedes compatible y no se puede escribir. Creo que la respuesta real depende del por qué detrás de esta pregunta y nunca supimos por qué.
mu es demasiado corto
@mu, llegué a esta pregunta después de hacer una similar, pero más general. Mi caso de "por qué" es que quiero asegurarme de que solo estoy realizando una acción (una transacción financiera, aunque sea pequeña) si el usuario tomó una acción afirmativa directa en la página.
Joe Enzminger
1

Solución de Vanila js:

document.querySelector('button').addEventListener('click', function (e){
    if(e.isTrusted){
        // real click.
    }else{
        // programmatic click
    }
});
Abhishek
fuente
-1

No voy a participar en la discusión intelectual, el código que me funcionó para filtrar .click()y .trigger('click')es-

$(document).on('click touchstart', '#my_target', function(e) {
    if (e.pageX && e.pageY) { // To check if it is not triggered by .click() or .trigger('click')
        //Then code goes here
    }
});
Sahu V Kumar
fuente