Długie naciśnięcie w JavaScript?

117

Czy można zaimplementować „długie naciśnięcie” w JavaScript (lub jQuery)? W jaki sposób?

tekst alternatywny
(źródło: 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
źródło
7
Prawdopodobnie utworzyłbym niestandardowe zdarzenie jQuery, używając twojego kodu jako bazy, więc możesz to zrobićjQuery(...).longclick(function() { ... });
Matti Virkkunen
1
Pytanie nie jest oznaczone tagiem jQuery, chociaż powinno. Pytanie dotyczy najpierw czystego rozwiązania Javascript, które wolę, lub opcjonalnie (w nawiasach) rozwiązania jQuery. Większość odpowiedzi wydaje się domyślnie przyjmować jQuery jako standardowe założenie. Zawsze gardziłem jQuery i ani razu go nie używałem, ani nie odczuwałem żadnej nieodpartej potrzeby. Niektórzy lubią go używać, to jest w porządku, dla każdego z nich. Odpowiedzi przy użyciu którejkolwiek z technik nic nie ranią. Ale ponieważ pytanie będzie akceptować rozwiązania jQuery, tag jQuery może przyciągnąć więcej oczu i miejmy nadzieję, że lepsze odpowiedzi. Odpowiedzi jQuery tutaj wydają się słabe.

Odpowiedzi:

159

Nie ma magii „jQuery”, tylko liczniki czasu 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
źródło
39
Czy ten ogień również się nie przeciągnie?
Gallal
11
@Gallal Prawdopodobnie byłoby to dość proste, aby zobaczyć, że dzwoniąc do clearTimeout(pressTimer)na mousemove, chyba że czegoś mi brakuje. Co prawda nie byłoby bezprecedensowe.
David John Welsh,
5
@DavidJohnWelsh Właśnie to, na co patrzyłem, nie chcesz jednak tylko poruszać myszą - stabilne trzymanie palca i brak ruchu 1px jest dość trudne! Musisz zastosować próg (jeśli mysz nie poruszyła się o 10px) itp. Szybko się komplikuje!
Ian
6
Pamiętaj, że jeśli spodziewasz się, że to zadziała na telefonach, często mają one własne domyślne zachowanie longpress (na przykład chrome na Androidzie pokazuje menu modalne z różnymi opcjami po długim naciśnięciu linku). Nie miałem dużo szczęścia, aby temu zapobiec, a szczerze mówiąc, ingerowanie w domyślne zachowanie przeglądarki i tak jest niczym ukrywanie.
dartacus
4
Chociaż jest to wybrana odpowiedź, tak naprawdę nie odpowiada na pytanie. Jest to zbyt uproszczone i naiwne. Każde długie wydarzenie prasowe musi dotyczyć wielu problemów, które ta odpowiedź ignoruje. 1) Odróżnij długie naciśnięcie od przeciągania od gestu od wielodotyku (tj. Powiększanie lub pomniejszanie przez szczypanie) 2) Anuluj, jeśli ruch poza elementem lub obszarem przeglądarki 3) Adresowanie domyślnego zachowania zaznaczania tekstu na znacznej liczbie platform i urządzeń 4) Zezwalaj konfigurowalny próg czułości i nie polegający na magicznych liczbach. Jest to szczególnie przydatne w przypadku problemów z dostępnością, ale nie wyłącznie.
34

Na podstawie odpowiedzi Maycow Moura napisałem to. Zapewnia również, że użytkownik nie wykonał prawego kliknięcia, co spowodowałoby długie naciśnięcie i działa na urządzeniach mobilnych. PRÓBNY

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

Powinieneś również dołączyć wskaźnik wykorzystujący animacje 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
źródło
Zrobiłem tę zmodyfikowaną wersję, aby robić coś ciągle, gdy przycisk jest wciśnięty jsfiddle, ale z jakiegoś powodu na Androidzie działa nawet po zatrzymaniu dotykania przycisku + ...
Xander
@Xander: Może dlatego, że :hoverstan jest lepki na urządzeniach dotykowych, może to również dotyczy tutaj.
kelunik
Cholera, zastanawiam się, czy istnieje sposób, aby przyciski zwiększania liczby - / + działały w witrynie mobilnej, która obsługuje długie naciśnięcia. Każda metoda, którą znajduję, obsługuje tylko wielokrotne klikanie, co jest problemem przy dużych liczbach. W każdym razie dzięki!
Xander
@Xander: Właściwie touchendpowinien odpalić IMO, nie ma powodu, żeby się kleił, kiedy jest to specjalny kod dla urządzeń dotykowych, może spróbuję czegoś jutro.
kelunik
1
Rozwiązałem problem w systemie Android. Naciśnięcie powoduje uruchomienie zarówno myszy, jak i startu dotykowego, dzięki czemu działają 2 timery, ale tylko 1 jest anulowany przez podniesienie palca. Zapakowany presstimer z if (presstimer === null), aby upewnić się, że timer nie był już aktywny.
Xander
16

Stworzyłem zdarzenie z długim naciśnięciem (0.5k czystego JavaScript), aby rozwiązać ten problem, dodaje pliklong-press zdarzenie do DOM.

Nasłuchiwać long-pressna dowolnym elemencie:

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

Nasłuchiwać long-pressna konkretnym elemencie:

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

Działa w IE9 +, Chrome, Firefox, Safari i hybrydowych aplikacjach mobilnych (Cordova i Ionic na iOS / Android)

Próbny

John Doherty
źródło
2
Świetnie, kolego !!
Jeff T.
1
To rozwiązanie małpa łata obiekt window.CustomEvent w nieco przypadkowy, niekompletny i niestandardowy sposób. Nie tworzy poprawnie właściwości tylko do odczytu jako tylko do odczytu, ale raczej do odczytu i zapisu. W szczególności brakuje w nim wartości returnValue, type, timeStamp i isTrusted. Nie rozwiązuje problemu przeciągania, gestów, powiększania lub pomniejszania przez szczypanie lub wielodotykowych niewypałów podczas długiego naciśnięcia, ani nie rozwiązuje problemu dużej liczby urządzeń i / lub platform, które domyślnie długie naciśnięcie powodują zaznaczenie tekstu nawet po 500 ms. W bibliotece brakuje wszystkich przypadków testowych dla tych warunków.
4
To Open Source, nie krępuj się współtworzyć projekt :)
John Doherty
@JohnDoherty świetnie! ale czy nadal możemy używać „onClick” z tym samym elementem?
Devashish
2
Nadal powinieneś otrzymać zdarzenie „onclick”, o ile długie naciśnięcie zostanie zwolnione, zanim włączy się licznik czasu „długiego naciśnięcia”
John Doherty
15

Chociaż wygląda to na dość proste do samodzielnego zaimplementowania z limitem czasu i kilkoma programami obsługi zdarzeń myszy, staje się nieco bardziej skomplikowane, gdy weźmiesz pod uwagę przypadki takie jak kliknięcie-przeciągnij-zwolnienie, obsługujące zarówno naciśnięcie, jak i długie naciśnięcie tego samego elementu i praca z urządzeniami dotykowymi, takimi jak iPad. Skończyło się na użyciu wtyczki longclick jQuery ( Github ), która zajmuje się tym za mnie. Jeśli potrzebujesz tylko obsługi urządzeń z ekranem dotykowym, takich jak telefony komórkowe, możesz również wypróbować zdarzenie taphold jQuery Mobile .

ʇsәɹoɈ
źródło
Link Github działa, ale projekt nie był aktualizowany od 2010 roku i nie działa z aktualnymi wersjami jquery. Jednak zastąpienie handle.apply przez dispatch.apply w kodzie źródłowym rozwiązuje ten problem.
arlomedia
11

Wtyczka jQuery. Po prostu włóż $(expression).longClick(function() { <your code here> });. Drugi parametr to czas wstrzymania; domyślny limit czasu to 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
źródło
nie jest to zatrzymywane w wezwaniu.
Champ
Cześć, stary, możemy to wykorzystać jako zdarzenie szkieletowe
user2075328
6

Dla programistów korzystających z wielu platform (Uwaga: Wszystkie udzielone dotychczas odpowiedzi nie będą działać na iOS) :

MouseUp / dół wydawało się działać dobrze na android - ale nie wszystkie urządzenia (tj samsung tab4). W ogóle nie działał na iOS .

Dalsze badania wydają się, że jest to spowodowane elementem posiadającym selekcję, a natywne powiększenie przeszkadza słuchaczowi.

Ten detektor zdarzeń umożliwia otwieranie obrazu miniatury w trybie ładowania początkowego, jeśli użytkownik przechowuje obraz przez 500 ms.

Używa responsywnej klasy obrazu, dlatego pokazuje większą wersję obrazu. Ten fragment kodu został w pełni przetestowany na (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
źródło
fajne rozwiązanie na iOS
eric xu
jak zapobiec dotknięciom rozpoczynającym się na miniaturze, ale kończącym się zwojem. innymi słowy, nie touchstart / end in place, ale dotyk, który rozpoczął się na elemencie z handlerem, ale kończy się zwójem
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;
    });
});

PRÓBNY

razz
źródło
2
W przypadku tego kodu longclick nie jest uruchamiany po upływie 500 ms. Użytkownik może umrzeć klikając myszką :). Długie kliknięcie jest uruchamiane tylko wtedy, gdy użytkownik przestanie klikać przycisk.
jedi
czy obejmowałoby to przypadek, gdy użytkownik zaczął przewijać, zamiast kończyć longpress w tym samym miejscu?
Akin Hwan
@AkinHwan Nie, zostanie wyzwolone tylko wtedy, gdy kliknięcie myszą zostanie zwolnione na tym samym elemencie.
razz
4

Odpowiedź Diodeusa jest niesamowita, ale uniemożliwia dodanie funkcji onClick, nigdy nie uruchomi funkcji wstrzymania, jeśli umieścisz przycisk onclick. Odpowiedź Razzaka jest prawie doskonała, ale funkcja wstrzymania uruchamia się tylko po najechaniu myszą i generalnie funkcja działa nawet wtedy, gdy użytkownik przytrzymuje.

Więc dołączyłem do obu i zrobiłem to:

$(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
źródło
co się stanie, jeśli użytkownik rozpocznie przewijanie po usunięciu kursora i nie zamierzał robić długiego naciśnięcia
Akin Hwan
4

W przypadku nowoczesnych przeglądarek mobilnych:

document.addEventListener('contextmenu', callback);

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

Kory Nunn
źródło
Lub dla JQuery użyj $ (selector) .bind ('contextmenu', function () {})
dfmiller
przestań używać bind()jquery 1.7+ = on()and unbind()=off()
dbinott
2

Możesz ustawić limit czasu dla tego elementu po naciśnięciu myszy i wyczyścić go po myszy w górę:

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

Dzięki temu każdy element ma swój własny limit czasu.

Gumbo
źródło
1
$(this).mouseup(function(){});nie usuwa obsługi zdarzeń, dodaje kolejny. Użyj .unbindzamiast tego.
Matti Virkkunen,
powinien używać off()teraz zamiast unbind.
dbinott
1

Możesz użyć taphold jquery-mobile. Dołącz plik jquery-mobile.js, a poniższy kod będzie działał poprawnie

$(document).on("pagecreate","#pagename",function(){
  $("p").on("taphold",function(){
   $(this).hide(); //your code
  });    
});
Prashant_M
źródło
To powinna być akceptowana odpowiedź, ponieważ jquery-mobile zapewnia dobrą stabilną strukturę
pasx
1

Najbardziej elegancka i czysta jest wtyczka jQuery: https://github.com/untill/jquery.longclick/ , dostępna również jako pakiet: https://www.npmjs.com/package/jquery.longclick .

Krótko mówiąc, używasz go w ten sposób:

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

Zaletą tej wtyczki jest to, że w przeciwieństwie do niektórych innych odpowiedzi tutaj, zdarzenia kliknięcia są nadal możliwe. Zwróć również uwagę, że występuje długie kliknięcie, podobnie jak długie dotknięcie urządzenia, przed najechaniem myszą. Więc to jest funkcja.

do
źródło
0

Dla mnie to działa z tym kodem (z 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
źródło
0

Możesz sprawdzić czas, aby zidentyfikować kliknięcie lub długie naciśnięcie [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
źródło
0

lubię to?

doc.addEeventListener("touchstart", function(){
    // your code ...
}, false);    
翁 沈 顺
źródło
0

Możesz używać jqueryzdarzeń dotykowych. ( patrz tutaj )

  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
źródło
0

Potrzebowałem czegoś na długie imprezy klawiszowe, więc napisałem to.

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
źródło
0

Myślę, że to może ci pomóc:

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
źródło