Appui long en JavaScript?

117

Est-il possible d'implémenter "appui long" en JavaScript (ou jQuery)? Comment?

texte alternatif
(source: 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
la source
7
Je créerais probablement un événement jQuery personnalisé en utilisant votre code comme base, vous pouvez donc le fairejQuery(...).longclick(function() { ... });
Matti Virkkunen
1
La question n'est pas balisée avec jQuery, bien qu'elle devrait l'être. La question demande d'abord une solution Javascript pure, que je préfère, ou éventuellement (entre parenthèses), une solution jQuery. La plupart des réponses semblent utiliser par défaut jQuery comme hypothèse standard. J'ai toujours méprisé jQuery et je ne l'ai jamais utilisé une seule fois, ni ressenti un besoin impérieux. Certains aiment l'utiliser, c'est bien, à chacun le leur. Les réponses utilisant l'une ou l'autre technique ne font aucun mal. Mais comme la question acceptera les solutions jQuery, une balise jQuery pourrait obtenir plus de globes oculaires et, espérons-le, de meilleures réponses. Les réponses jQuery ici semblent terne.

Réponses:

159

Il n'y a pas de magie «jQuery», juste des minuteries 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
la source
39
Est-ce que ce feu ne ferait pas aussi feu?
Gallal
11
@Gallal On peut supposer que ce serait assez simple de voir que en appelant clearTimeout(pressTimer)à mousemove, à moins que je me manque quelque chose. Ce qui, certes, ne serait guère sans précédent.
David John Welsh
5
@DavidJohnWelsh Juste ce que j'ai regardé, vous ne voulez pas seulement bouger la souris - vous tenir fermement le doigt et ne pas bouger 1px est assez difficile! Vous devez appliquer un seuil (si la souris n'a pas bougé de 10 pixels) etc. Cela se complique assez rapidement!
Ian
6
Gardez à l'esprit que si vous vous attendez à ce que cela fonctionne sur les téléphones, ils ont souvent leur propre comportement Longpress par défaut (Chrome sur Android, par exemple, affiche un menu modal avec diverses options lorsque vous appuyez longuement sur un lien). Je n'ai pas eu beaucoup de chance pour empêcher cela, et pour être honnête, interférer avec le comportement par défaut du navigateur ne cache rien de toute façon.
dartacus
4
Bien que ce soit la réponse choisie, elle ne répond pas vraiment à la question. C'est trop simpliste et naïf. Tout événement de presse longue doit résoudre plusieurs problèmes que cette réponse ignore. 1) Distinguer un appui long du glissement du geste du multi-touch (c'est-à-dire un zoom avant ou arrière) 2) Annuler si le mouvement en dehors de l'élément ou de la zone du navigateur 3) Adresser le comportement par défaut de la sélection de texte sur un nombre significatif de plates-formes et d'appareils 4) Autoriser un seuil configurable pour la sensibilité et ne pas compter sur des nombres magiques. Particulièrement utile pour les problèmes d'accessibilité, mais non exclusifs.
34

Sur la base de la réponse de Maycow Moura, j'ai écrit ceci. Cela garantit également que l'utilisateur n'a pas fait un clic droit, ce qui déclencherait une pression longue et fonctionnerait sur les appareils mobiles. DEMO

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);

Vous devriez également inclure un indicateur utilisant des animations 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
la source
J'ai fait cette version modifiée, pour faire quelque chose en permanence pendant que le bouton est maintenu enfoncé jsfiddle mais pour une raison quelconque sur Android, il fonctionne même après que vous arrêtez de toucher le bouton + ...
Xander
@Xander: Peut-être parce que l' :hoverétat est collant sur les appareils tactiles, peut-être que cela s'applique également ici.
kelunik le
Dang, je me demande s'il existe un moyen de faire fonctionner les boutons d'incrémentation - / + sur un site mobile prenant en charge de longues pressions. Chaque méthode que je trouve ne supporte que le fait de cliquer à plusieurs reprises, ce qui est pénible pour un grand nombre. Merci quand même!
Xander le
@Xander: En fait, touchendsi je devais licencier l'OMI, il n'y a aucune raison de le coller quand c'est un code spécial pour les appareils tactiles, peut-être que j'essaierai quelque chose demain.
kelunik le
1
J'ai compris le problème sur Android. Appuyer sur déclenche à la fois la descente de la souris et le démarrage tactile, de sorte qu'il y avait 2 minuteries en cours d'exécution, mais seulement 1 était annulée en soulevant votre doigt. Presstimer enveloppé avec if (presstimer === null) pour s'assurer que le timer n'était pas déjà actif.
Xander
16

J'ai créé un événement de presse longue (JavaScript pur 0,5k) pour résoudre ce problème, il ajoute un long-pressévénement au DOM.

Écoutez un long-presssur n'importe quel élément:

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

Écoutez un long-presssur un élément spécifique :

// 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);
});

Fonctionne dans les applications mobiles IE9 +, Chrome, Firefox, Safari et hybrides (Cordova et Ionic sur iOS / Android)

Démo

John Doherty
la source
2
Génial, mon pote !!
Jeff T.
1
Cette solution monkey corrige l'objet window.CustomEvent de manière quelque peu aléatoire, incomplète et non standard. Il ne crée pas correctement des propriétés en lecture seule en lecture seule mais plutôt en lecture-écriture. Il manque spécifiquement returnValue, type, timeStamp et isTrusted. Il ne traite pas du glissement, des gestes, du zoom avant ou arrière par pincement ou des ratés multi-touch de la pression longue, ni du problème d'un grand nombre d'appareils et / ou de plates-formes qui appuient longuement par défaut sur la sélection de texte, même à 500 ms. Il manque à la bibliothèque tous les cas de test pour ces conditions.
4
C'est Open Source, n'hésitez pas à contribuer au projet :)
John Doherty
@JohnDoherty super! mais pouvons-nous toujours utiliser "onClick" avec le même élément?
Devashish
2
Vous devriez toujours obtenir l'événement `` onclick '' tant que la longue pression est relâchée avant que le minuteur `` long-press-delay '' ne démarre
John Doherty
15

Bien que cela semble assez simple pour être implémenté par vous-même avec un délai d'expiration et quelques gestionnaires d'événements de souris, cela devient un peu plus compliqué lorsque vous considérez des cas comme cliquer-glisser-relâcher, prenant en charge à la fois appuyer et appuyer longuement sur le même élément et travailler avec des appareils tactiles comme l'iPad. J'ai fini par utiliser le plugin jQuery longclick ( Github ), qui s'occupe de ça pour moi. Si vous devez uniquement prendre en charge les appareils à écran tactile tels que les téléphones mobiles, vous pouvez également essayer l' événement jQuery Mobile taphold .

ʇsәɹoɈ
la source
Le lien Github fonctionne, mais le projet n'a pas été mis à jour depuis 2010 et ne fonctionne pas avec les versions actuelles de jquery. Cependant, le remplacement de handle.apply par dispatch.apply dans le code source le corrige.
arlomedia
11

plugin jQuery. Mettez juste $(expression).longClick(function() { <your code here> });. Le deuxième paramètre est la durée de maintien; le délai d'expiration par défaut est de 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
la source
cela n'est pas conservé dans l'appel.
Champ
salut Bro pouvons-nous l'utiliser comme un événement de base
user2075328
6

Pour les développeurs multiplateformes (Remarque Toutes les réponses données jusqu'à présent ne fonctionneront pas sur iOS) :

Mouseup / down semblait fonctionner correctement sur Android - mais pas sur tous les appareils (samsung tab4). Ne fonctionnait pas du tout sur iOS .

Des recherches plus poussées, il semble que cela soit dû à l'élément sélectionné et que le grossissement natif interrompt l'auditeur.

Cet écouteur d'événements permet d'ouvrir une image miniature dans un modal d'amorçage, si l'utilisateur conserve l'image pendant 500 ms.

Il utilise une classe d'image réactive montrant ainsi une version plus grande de l'image. Ce morceau de code a été entièrement testé sur (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
la source
belle solution pour iOS
eric xu
comment pourrais-je empêcher les touches qui commencent sur la vignette, mais disons finir par être un défilement. en d'autres termes, pas un touchstart / end en place, mais une touche qui a commencé sur l'élément avec le gestionnaire, mais qui finit par être un parchemin
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;
    });
});

DEMO

razz
la source
2
Avec ce code, le clic long n'est pas déclenché au bout de 500 ms. L'utilisateur peut mourir en cliquant sur la souris :). Le clic long n'est déclenché que si l'utilisateur s'arrête pour cliquer sur le bouton.
jedi
cela couvrirait-il le cas lorsqu'un utilisateur a commencé à faire défiler au lieu de terminer sa longue impression au même endroit?
Akin Hwan
@AkinHwan Non, il ne serait déclenché que si le clic de la souris était relâché sur le même élément.
razz
4

La réponse de Diodeus est géniale, mais elle vous empêche d'ajouter une fonction onClick, elle n'exécutera jamais la fonction hold si vous mettez un onclick. Et la réponse du Razzak est presque parfaite, mais il exécute la fonction de maintien uniquement sur la souris, et généralement, la fonction s'exécute même si l'utilisateur continue de tenir.

Alors, j'ai rejoint les deux et j'ai fait ceci:

$(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
la source
et si l'utilisateur commençait à faire défiler après mousedown et n'avait pas l'intention de faire une longue pression
Akin Hwan
4

Pour les navigateurs mobiles modernes:

document.addEventListener('contextmenu', callback);

https://developer.mozilla.org/en-US/docs/Web/Events/contextmenu

Kory Nunn
la source
Ou pour JQuery, utilisez $ (selector) .bind ('contextmenu', function () {})
dfmiller
arrêter d'utiliser bind()jquery 1.7+ = on()and unbind()=off()
dbinott
2

Vous pouvez définir le délai d'expiration de cet élément en appuyant sur la souris et l'effacer en haut de la souris:

$("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;
});

Avec cela, chaque élément obtient son propre délai d'expiration.

Gombo
la source
1
$(this).mouseup(function(){});ne supprime pas le gestionnaire d'événements, il en ajoute un autre. Utilisez .unbindplutôt.
Matti Virkkunen
devrait utiliser off()maintenant au lieu de délier.
dbinott le
1

Vous pouvez utiliser le taphold de jquery-mobile. Incluez le jquery-mobile.js et le code suivant fonctionnera correctement

$(document).on("pagecreate","#pagename",function(){
  $("p").on("taphold",function(){
   $(this).hide(); //your code
  });    
});
Prashant_M
la source
Cela devrait être la réponse acceptée car jquery-mobile fournit un bon framework stable
pasx
1

Le plus élégant et le plus propre est un plugin jQuery: https://github.com/untill/jquery.longclick/ , également disponible en packacke: https://www.npmjs.com/package/jquery.longclick .

Bref, vous l'utilisez comme ceci:

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

L'avantage de ce plugin est que, contrairement à certaines des autres réponses ici, les événements de clic sont toujours possibles. Notez également qu'un clic long se produit, tout comme un appui long sur un appareil, avant la souris. Donc, c'est une fonctionnalité.

jusqu'à
la source
0

Pour moi, cela fonctionne avec ce code (avec 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
la source
0

Vous pouvez vérifier l’heure d’identification du clic ou de la pression longue [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
la source
0

comme ça?

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

Vous pouvez utiliser les jqueryévénements Touch. ( voir ici )

  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
la source
0

J'avais besoin de quelque chose pour les événements clavier de longue durée, alors j'ai écrit ceci.

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
la source
0

Je pense que cela peut vous aider:

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
la source