¿Pulsación larga en JavaScript?

117

¿Es posible implementar "pulsación larga" en JavaScript (o jQuery)? ¿Cómo?

texto alternativo
(fuente: androinica.com )

HTML

<a href="" title="">Long press</a>

JavaScript

$("a").mouseup(function(){
  // Clear timeout
  return false;
}).mousedown(function(){
  // Set timeout
  return false; 
});
Randy Mayer
fuente
7
Probablemente crearía un evento jQuery personalizado usando su código como base, por lo que puede hacerlojQuery(...).longclick(function() { ... });
Matti Virkkunen
1
La pregunta no está etiquetada con jQuery, aunque debería estarlo. La pregunta pide primero una solución de Javascript pura, que prefiero, u opcionalmente (entre paréntesis), una solución de jQuery. La mayoría de las respuestas parecen estar predeterminadas en jQuery como suposición estándar. Siempre he despreciado jQuery y nunca lo usé ni sentí ninguna necesidad imperiosa de usarlo. Algunos disfrutan usándolo, eso está bien, para cada uno lo suyo. Las respuestas que usan cualquiera de las técnicas no hacen daño. Pero dado que la pregunta aceptará soluciones de jQuery, una etiqueta de jQuery podría obtener más ojos y, con suerte, mejores respuestas. Las respuestas de jQuery aquí parecen mediocres.

Respuestas:

159

No hay magia de 'jQuery', solo temporizadores de JavaScript.

var pressTimer;

$("a").mouseup(function(){
  clearTimeout(pressTimer);
  // Clear timeout
  return false;
}).mousedown(function(){
  // Set timeout
  pressTimer = window.setTimeout(function() { ... Your Code ...},1000);
  return false; 
});
Diodeus - James MacFarlane
fuente
39
¿No se dispararía esto también?
Gallal
11
@Gallal Es de suponer que sería bastante fácil de ver a esa llamando clearTimeout(pressTimer)a mousemove, a menos que me falta algo. Lo cual, ciertamente, no tendría precedentes.
David John Welsh
5
@DavidJohnWelsh Justo lo que he estado viendo, sin embargo, no solo quieres que el mouse se mueva: ¡mantener el dedo firme y sin mover 1px es bastante difícil! Necesita aplicar un umbral (si el mouse no se ha movido 10px), etc. ¡Se complica bastante rápido!
Ian
6
Tenga en cuenta que si espera que esto funcione en teléfonos, a menudo tienen su propio comportamiento predeterminado de pulsación prolongada (Chrome en Android, por ejemplo, muestra un menú modal con varias opciones cuando mantiene pulsado un enlace). No tuve mucha suerte previniendo esto, y para ser honesto, interferir con el comportamiento predeterminado del navegador es esconder nada de todos modos.
dartacus
4
Aunque esta es la respuesta seleccionada, en realidad no responde a la pregunta. Es demasiado simplista e ingenuo. Cualquier evento de pulsación prolongada debe abordar varios problemas que esta respuesta ignora. 1) Distinguir presionar prolongadamente de arrastrar de gestos de multitáctil (es decir, acercar o alejar el zoom) 2) Cancelar si se mueve fuera del elemento o área del navegador 3) Abordar el comportamiento predeterminado de la selección de texto en una cantidad significativa de plataformas y dispositivos 4) Permitir un umbral configurable para la sensibilidad y no depender de números mágicos. Particularmente útil para, pero no exclusivo, problemas de accesibilidad.
34

Basado en la respuesta de Maycow Moura, escribí esto. También asegura que el usuario no hizo un clic derecho, lo que activaría una pulsación larga y funciona en dispositivos móviles. MANIFESTACIÓN

var node = document.getElementsByTagName("p")[0];
var longpress = false;
var presstimer = null;
var longtarget = null;

var cancel = function(e) {
    if (presstimer !== null) {
        clearTimeout(presstimer);
        presstimer = null;
    }

    this.classList.remove("longpress");
};

var click = function(e) {
    if (presstimer !== null) {
        clearTimeout(presstimer);
        presstimer = null;
    }

    this.classList.remove("longpress");

    if (longpress) {
        return false;
    }

    alert("press");
};

var start = function(e) {
    console.log(e);

    if (e.type === "click" && e.button !== 0) {
        return;
    }

    longpress = false;

    this.classList.add("longpress");

    if (presstimer === null) {
        presstimer = setTimeout(function() {
            alert("long click");
            longpress = true;
        }, 1000);
    }

    return false;
};

node.addEventListener("mousedown", start);
node.addEventListener("touchstart", start);
node.addEventListener("click", click);
node.addEventListener("mouseout", cancel);
node.addEventListener("touchend", cancel);
node.addEventListener("touchleave", cancel);
node.addEventListener("touchcancel", cancel);

También deberías incluir algún indicador usando animaciones CSS:

p {
    background: red;
    padding: 100px;
}

.longpress {
    -webkit-animation: 1s longpress;
            animation: 1s longpress;
}

@-webkit-keyframes longpress {
    0%, 20% { background: red; }
    100% { background: yellow; }
}

@keyframes longpress {
    0%, 20% { background: red; }
    100% { background: yellow; }
}
Kelunik
fuente
Hice esta versión modificada, para hacer algo constantemente mientras se mantiene presionado el botón jsfiddle, pero por alguna razón en Android se ejecuta incluso después de que dejas de tocar el botón + ...
Xander
@Xander: Quizás porque el :hoverestado es pegajoso en los dispositivos táctiles, quizás eso también se aplique aquí.
kelunik
Maldita sea, me pregunto si hay alguna forma de hacer que los botones de incremento numérico - / + funcionen en un sitio móvil que admita pulsaciones largas. Cada método que encuentro solo admite tener que hacer clic repetidamente, lo cual es una molestia para grandes números. Pero gracias!
Xander
@Xander: En realidad, touchenddebería disparar la OMI, no hay razón para tenerlo pegajoso cuando es un código especial para dispositivos táctiles, tal vez intente algo mañana.
Kelunik
1
Resolví el problema en Android. Al presionar, se dispara el mousedown y el touchstart, por lo que tenía 2 temporizadores en ejecución, pero solo 1 se canceló levantando el dedo. Presstimer envuelto con if (presstimer === null) para asegurarse de que el temporizador no esté activo.
Xander
25

Puede utilizar el evento taphold de la API móvil jQuery.

jQuery("a").on("taphold", function( event ) { ... } )
doganak
fuente
2
Tenga en cuenta: jquery mobile entra en conflicto con jquery ui. Véase también stackoverflow.com/questions/24379514/…
Marcel Verwey
16

Creé largo de prensa del evento (0.5K JavaScript puro) para resolver esto, se agrega un long-pressevento para el DOM.

Escuche long-pressen cualquier elemento:

// the event bubbles, so you can listen at the root level
document.addEventListener('long-press', function(e) {
  console.log(e.target);
});

Escuche long-presssobre un elemento específico :

// get the element
var el = document.getElementById('idOfElement');

// add a long-press event listener
el.addEventListener('long-press', function(e) {

    // stop the event from bubbling up
    e.preventDefault()

    console.log(e.target);
});

Funciona en IE9 +, Chrome, Firefox, Safari y aplicaciones móviles híbridas (Cordova e Ionic en iOS / Android)

Manifestación

John Doherty
fuente
2
¡¡Ay, amigo !!
Jeff T.
1
Esta solución mono parchea el objeto window.CustomEvent de una manera algo desordenada, incompleta y no estándar. No crea correctamente propiedades de solo lectura como solo lectura, sino de lectura y escritura. Falta específicamente returnValue, type, timeStamp e isTrusted. No aborda la función de arrastrar, hacer gestos, acercar o alejar el zoom, ni los fallos de disparo multitáctiles de pulsación prolongada, ni aborda el problema de una gran cantidad de dispositivos y / o plataformas que de forma predeterminada pulsación prolongada para la selección de texto incluso a 500 ms. A la biblioteca le faltan todos y cada uno de los casos de prueba para estas condiciones.
4
Es de código abierto, siéntase libre de contribuir al proyecto :)
John Doherty
@JohnDoherty ¡genial! pero, ¿podemos seguir usando "onClick" con el mismo elemento?
Devashish
2
Aún debería obtener el evento 'onclick' siempre que se suelte la presión prolongada antes de que se active el temporizador de 'pulsación prolongada-demora'
John Doherty
15

Si bien parece lo suficientemente simple como para implementarlo por su cuenta con un tiempo de espera y un par de controladores de eventos del mouse, se vuelve un poco más complicado cuando considera casos como hacer clic, arrastrar y soltar, admitiendo presionar y presionar prolongadamente en el mismo elemento y trabajar con dispositivos táctiles como el iPad. Terminé usando el complemento jQuery longclick ( Github ), que se encarga de esas cosas por mí. Si solo necesita admitir dispositivos con pantalla táctil como teléfonos móviles, también puede probar el evento taphold de jQuery Mobile .

ʇsәɹoɈ
fuente
El enlace de Github funciona, pero el proyecto no se ha actualizado desde 2010 y no funciona con las versiones actuales de jquery. Sin embargo, reemplazar handle.apply con dispatch.apply en el código fuente lo corrige.
arlomedia
11

Complemento jQuery. Solo ponlo $(expression).longClick(function() { <your code here> });. El segundo parámetro es la duración de la retención; el tiempo de espera predeterminado es 500 ms.

(function($) {
    $.fn.longClick = function(callback, timeout) {
        var timer;
        timeout = timeout || 500;
        $(this).mousedown(function() {
            timer = setTimeout(function() { callback(); }, timeout);
            return false;
        });
        $(document).mouseup(function() {
            clearTimeout(timer);
            return false;
        });
    };

})(jQuery);
piwko28
fuente
esto no se retiene en la llamada.
Champ
hola hermano, ¿podemos usarlo como un evento principal?
user2075328
6

Para desarrolladores multiplataforma (tenga en cuenta que todas las respuestas dadas hasta ahora no funcionarán en iOS) :

Mouseup / down parecía funcionar bien en Android , pero no en todos los dispositivos, es decir, (samsung tab4). No funcionó en absoluto en iOS .

Investigaciones posteriores parecen que esto se debe a que el elemento tiene selección y la ampliación nativa interrumpe al oyente.

Este detector de eventos permite abrir una imagen en miniatura en un modal de arranque, si el usuario retiene la imagen durante 500 ms.

Utiliza una clase de imagen receptiva, por lo que muestra una versión más grande de la imagen. Esta pieza de código ha sido completamente probada (iPad / Tab4 / TabA / Galaxy4):

var pressTimer;  
$(".thumbnail").on('touchend', function (e) {
   clearTimeout(pressTimer);
}).on('touchstart', function (e) {
   var target = $(e.currentTarget);
   var imagePath = target.find('img').attr('src');
   var title = target.find('.myCaption:visible').first().text();
   $('#dds-modal-title').text(title);
   $('#dds-modal-img').attr('src', imagePath);
   // Set timeout
   pressTimer = window.setTimeout(function () {
      $('#dds-modal').modal('show');
   }, 500)
});
tyler_mitchell
fuente
buena solución para iOS
eric xu
¿Cómo evitaría los toques que comienzan en la miniatura, pero dicen que terminan siendo un pergamino? en otras palabras, no un touchstart / end en su lugar, sino un toque que comenzó en el elemento con handler, pero termina siendo un scroll
Akin Hwan
5
$(document).ready(function () {
    var longpress = false;

    $("button").on('click', function () {
        (longpress) ? alert("Long Press") : alert("Short Press");
    });

    var startTime, endTime;
    $("button").on('mousedown', function () {
        startTime = new Date().getTime();
    });

    $("button").on('mouseup', function () {
        endTime = new Date().getTime();
        longpress = (endTime - startTime < 500) ? false : true;
    });
});

MANIFESTACIÓN

razz
fuente
2
Con este código, el clic largo no se dispara al final de 500 ms. El usuario puede morir haciendo clic en el mouse :). El clic largo se dispara solo si el usuario deja de hacer clic en el botón.
jedi
¿Cubrirá esto el caso cuando un usuario comienza a desplazarse en lugar de terminar su pulsación larga en el mismo lugar?
Akin Hwan
@AkinHwan No, solo se activará si se suelta el clic del mouse sobre el mismo elemento.
razz
4

La respuesta de Diodeus es increíble, pero le impide agregar una función onClick, nunca ejecutará la función hold si pones un onclick. Y la respuesta de Razzak es casi perfecta, pero ejecuta la función de retención solo con el mouse hacia arriba y, en general, la función se ejecuta incluso si el usuario sigue presionando.

Entonces, me uní a ambos e hice esto:

$(element).on('click', function () {
    if(longpress) { // if detect hold, stop onclick function
        return false;
    };
});

$(element).on('mousedown', function () {
    longpress = false; //longpress is false initially
    pressTimer = window.setTimeout(function(){
    // your code here

    longpress = true; //if run hold function, longpress is true
    },1000)
});

$(element).on('mouseup', function () {
    clearTimeout(pressTimer); //clear time on mouseup
});
Maycow Moura
fuente
¿Qué pasa si el usuario comienza a desplazarse después de presionar el mouse y no tiene la intención de hacer una pulsación larga
Akin Hwan
2

Puede establecer el tiempo de espera para ese elemento con el mouse hacia abajo y borrarlo con el mouse hacia arriba:

$("a").mousedown(function() {
    // set timeout for this element
    var timeout = window.setTimeout(function() { /* … */ }, 1234);
    $(this).mouseup(function() {
        // clear timeout for this element
        window.clearTimeout(timeout);
        // reset mouse up event handler
        $(this).unbind("mouseup");
        return false;
    });
    return false;
});

Con esto, cada elemento obtiene su propio tiempo de espera.

Gumbo
fuente
1
$(this).mouseup(function(){});no elimina el controlador de eventos, agrega otro. Úselo en su .unbindlugar.
Matti Virkkunen
debería usar off()ahora en lugar de desvincular.
dbinott
1

Puede usar el taphold de jquery-mobile. Incluya jquery-mobile.js y el siguiente código funcionará bien

$(document).on("pagecreate","#pagename",function(){
  $("p").on("taphold",function(){
   $(this).hide(); //your code
  });    
});
Prashant_M
fuente
Esta debe ser la respuesta aceptada desde jquery-móvil proporciona un marco estable buena
pasx
1

Lo más elegante y limpio es un complemento de jQuery: https://github.com/untill/jquery.longclick/ , también disponible como packacke: https://www.npmjs.com/package/jquery.longclick .

En resumen, lo usas así:

$( 'button').mayTriggerLongClicks().on( 'longClick', function() { your code here } );

La ventaja de este complemento es que, a diferencia de algunas de las otras respuestas aquí, los eventos de clic aún son posibles. Tenga en cuenta también que se produce un clic largo, al igual que un toque prolongado en un dispositivo, antes del mouseup. Entonces, esa es una característica.

hasta
fuente
0

Para mí es trabajar con ese código (con jQuery):

var int       = null,
    fired     = false;

var longclickFilm = function($t) {
        $body.css('background', 'red');
    },
    clickFilm = function($t) {
        $t  = $t.clone(false, false);
        var $to = $('footer > div:first');
        $to.find('.empty').remove();
        $t.appendTo($to);
    },
    touchStartFilm = function(event) {
        event.preventDefault();
        fired     = false;
        int       = setTimeout(function($t) {
            longclickFilm($t);
            fired = true;
        }, 2000, $(this)); // 2 sec for long click ?
        return false;
    },
    touchEndFilm = function(event) {
        event.preventDefault();
        clearTimeout(int);
        if (fired) return false;
        else  clickFilm($(this));
        return false;
    };

$('ul#thelist .thumbBox')
    .live('mousedown touchstart', touchStartFilm)
    .live('mouseup touchend touchcancel', touchEndFilm);
molokoloco
fuente
0

Puede verificar el tiempo para identificar Click o Long Press [jQuery]

function AddButtonEventListener() {
try {
    var mousedowntime;
    var presstime;
    $("button[id$='" + buttonID + "']").mousedown(function() {
        var d = new Date();
        mousedowntime = d.getTime();
    });
    $("button[id$='" + buttonID + "']").mouseup(function() {
        var d = new Date();
        presstime = d.getTime() - mousedowntime;
        if (presstime > 999/*You can decide the time*/) {
            //Do_Action_Long_Press_Event();
        }
        else {
            //Do_Action_Click_Event();
        }
    });
}
catch (err) {
    alert(err.message);
}
} 
Derin
fuente
0

¿Me gusta esto?

doc.addEeventListener("touchstart", function(){
    // your code ...
}, false);    
翁 沈 顺
fuente
0

Puede utilizar jqueryeventos táctiles. ( ver aquí )

  let holdBtn = $('#holdBtn')
  let holdDuration = 1000
  let holdTimer

  holdBtn.on('touchend', function () {
    // finish hold
  });
  holdBtn.on('touchstart', function () {
    // start hold
    holdTimer = setTimeout(function() {
      //action after certain time of hold
    }, holdDuration );
  });
Irteza Asad
fuente
0

Necesitaba algo para eventos de teclado de pulsación larga, así que escribí esto.

var longpressKeys = [13];
var longpressTimeout = 1500;
var longpressActive = false;
var longpressFunc = null;

document.addEventListener('keydown', function(e) {
    if (longpressFunc == null && longpressKeys.indexOf(e.keyCode) > -1) {
        longpressFunc = setTimeout(function() {
            console.log('longpress triggered');
            longpressActive = true;
        }, longpressTimeout);

    // any key not defined as a longpress
    } else if (longpressKeys.indexOf(e.keyCode) == -1) {
        console.log('shortpress triggered');
    }
});

document.addEventListener('keyup', function(e) {
    clearTimeout(longpressFunc);
    longpressFunc = null;

    // longpress key triggered as a shortpress
    if (!longpressActive && longpressKeys.indexOf(e.keyCode) > -1) {
        console.log('shortpress triggered');
    }
    longpressActive = false;
});
Brad.Smith
fuente
0

Creo que esto puede ayudarte:

var image_save_msg = 'You Can Not Save images!';
var no_menu_msg = 'Context Menu disabled!';
var smessage = "Content is protected !!";

function disableEnterKey(e) {
    if (e.ctrlKey) {
        var key;
        if (window.event)
            key = window.event.keyCode; //IE
        else
            key = e.which; //firefox (97)
        //if (key != 17) alert(key);
        if (key == 97 || key == 65 || key == 67 || key == 99 || key == 88 || key == 120 || key == 26 || key == 85 || key == 86 || key == 83 || key == 43) {
            show_wpcp_message('You are not allowed to copy content or view source');
            return false;
        } else
            return true;
    }
}

function disable_copy(e) {
    var elemtype = e.target.nodeName;
    var isSafari = /Safari/.test(navigator.userAgent) && /Apple Computer/.test(navigator.vendor);
    elemtype = elemtype.toUpperCase();
    var checker_IMG = '';
    if (elemtype == "IMG" && checker_IMG == 'checked' && e.detail >= 2) {
        show_wpcp_message(alertMsg_IMG);
        return false;
    }
    if (elemtype != "TEXT" && elemtype != "TEXTAREA" && elemtype != "INPUT" && elemtype != "PASSWORD" && elemtype != "SELECT" && elemtype != "OPTION" && elemtype != "EMBED") {
        if (smessage !== "" && e.detail == 2)
            show_wpcp_message(smessage);

        if (isSafari)
            return true;
        else
            return false;
    }
}

function disable_copy_ie() {
    var elemtype = window.event.srcElement.nodeName;
    elemtype = elemtype.toUpperCase();
    if (elemtype == "IMG") {
        show_wpcp_message(alertMsg_IMG);
        return false;
    }
    if (elemtype != "TEXT" && elemtype != "TEXTAREA" && elemtype != "INPUT" && elemtype != "PASSWORD" && elemtype != "SELECT" && elemtype != "OPTION" && elemtype != "EMBED") {
        //alert(navigator.userAgent.indexOf('MSIE'));
        //if (smessage !== "") show_wpcp_message(smessage);
        return false;
    }
}

function reEnable() {
    return true;
}
document.onkeydown = disableEnterKey;
document.onselectstart = disable_copy_ie;
if (navigator.userAgent.indexOf('MSIE') == -1) {
    document.onmousedown = disable_copy;
    document.onclick = reEnable;
}

function disableSelection(target) {
    //For IE This code will work
    if (typeof target.onselectstart != "undefined")
        target.onselectstart = disable_copy_ie;

    //For Firefox This code will work
    else if (typeof target.style.MozUserSelect != "undefined") {
        target.style.MozUserSelect = "none";
    }

    //All other  (ie: Opera) This code will work
    else
        target.onmousedown = function() {
            return false
        }
    target.style.cursor = "default";
}
// on_body_load

window.onload = function() {
    disableSelection(document.body);
};



// disable_Right_Click



document.ondragstart = function() {
    return false;
}

function nocontext(e) {
    return false;
}
document.oncontextmenu = nocontext;

harvansh sainy
fuente