Долгое нажатие в JavaScript?

117

Можно ли реализовать «долгое нажатие» в JavaScript (или jQuery)? Как?

альтернативный текст
(источник: androinica.com )

HTML

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

JavaScript

$("a").mouseup(function(){
  // Clear timeout
  return false;
}).mousedown(function(){
  // Set timeout
  return false; 
});
Рэнди Майер
источник
7
Я бы, вероятно, создал пользовательское событие jQuery, используя ваш код в качестве основы, так что вы можете просто сделатьjQuery(...).longclick(function() { ... });
Матти Вирккунен
1
Вопрос не помечен jQuery, хотя должен быть. Вопрос касается сначала решения на чистом Javascript, которое я предпочитаю, или, при желании (в скобках), решения jQuery. Большинство ответов, по-видимому, по умолчанию использует jQuery в качестве стандартного предположения. Я всегда презирал jQuery, никогда не использовал его и не чувствовал в нем острой необходимости. Некоторым нравится его использовать, это нормально, каждому свое. Ответы с использованием любого из этих методов ничего не повредят. Но поскольку вопрос будет принимать решения jQuery, тег jQuery может привлечь больше внимания и, надеюсь, получить лучшие ответы. Ответы jQuery здесь кажутся тусклыми.

Ответы:

159

Нет никакой магии jQuery, только таймеры 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; 
});
Диодей - Джеймс Макфарлейн
источник
39
Разве это не сработает и на тормозе?
Галлал,
11
@Gallal Предположительно это будет достаточно просто посмотреть на что, позвонив clearTimeout(pressTimer)на mousemove, если я что - то не хватает. Что, надо признать, вряд ли было бы беспрецедентным.
Дэвид Джон Уэлш
5
@DavidJohnWelsh Как раз то, на что я смотрел, вы не просто хотите, чтобы мышь двигалась - удерживать палец неподвижно и не двигать 1px довольно сложно! Вам нужно применить порог (если мышь не переместилась на 10 пикселей) и т.д. Довольно быстро усложняется!
Ян
6
Имейте в виду, что если вы ожидаете, что это будет работать на телефонах, они часто имеют собственное поведение при длительном нажатии по умолчанию (например, Chrome на Android показывает модальное меню с различными параметрами, когда вы долго нажимаете ссылку). Мне не очень повезло предотвратить это, и, честно говоря, вмешательство в поведение браузера по умолчанию в любом случае ничего не значит.
dartacus 02
4
Хотя это выбранный ответ, на самом деле он не отвечает на вопрос. Это слишком упрощенно и наивно. Любое длительное пресс-мероприятие должно затрагивать несколько вопросов, которые игнорируются в этом ответе. 1) Отличить длительное нажатие от перетаскивания от жеста от мультисенсорного ввода (например, увеличение или уменьшение масштаба) 2) Отмена при перемещении за пределы элемента или области браузера 3) Устранение поведения выделения текста по умолчанию на значительном количестве платформ и устройств 4) Разрешить настраиваемый порог чувствительности, не полагающийся на магические числа. Особенно полезно, но не только для проблем доступности.
34

Основываясь на ответе Maycow Moura, я написал это. Это также гарантирует, что пользователь не щелкнет правой кнопкой мыши, что вызовет длительное нажатие и работает на мобильных устройствах. 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);

Вы также должны включить некоторый индикатор, использующий анимацию 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
источник
Я сделал эту модифицированную версию, чтобы делать что-то постоянно, пока кнопка удерживается jsfiddle, но по какой-то причине на Android она работает даже после того, как вы перестаете касаться кнопки + ...
Ксандер
@Xander: Может быть, из-за того, что :hoverна сенсорных устройствах состояние липкое, может быть, это также применимо и здесь.
kelunik 01
Черт возьми, мне интересно, есть ли способ заставить кнопки увеличения числа - / +, работающие на мобильном сайте, которые поддерживают долгое нажатие. Каждый метод, который я нахожу, поддерживает только многократное нажатие, что является проблемой для огромных чисел. Спасибо хоть!
Ксандер
@Xander: На самом деле, touchendдолжен запустить IMO, нет причин, чтобы он был липким, когда это специальный код для сенсорных устройств, может быть, я попробую что-нибудь завтра.
kelunik 01
1
Разобрался в проблеме на Android. Нажатие запускает и mousedown, и touchstart, поэтому у него было 2 запущенных таймера, но только один отменялся, поднимая палец. Обернутый пресс-таймер с if (presstimer === null), чтобы убедиться, что таймер еще не активен.
Ксандер
25

Вы можете использовать событие taphold мобильного API jQuery.

jQuery("a").on("taphold", function( event ) { ... } )
doganak
источник
2
Обратите внимание: jquery mobile конфликтует с jquery ui. См. Также stackoverflow.com/questions/24379514/…
Марсель Вервей,
16

Я создал событие с длительным нажатием (0,5k чистого JavaScript), чтобы решить эту проблему, оно добавляет long-pressсобытие в DOM.

Прослушайте long-pressна любом элементе:

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

Слушайте для long-pressна конкретного элемента:

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

Работает в IE9 +, Chrome, Firefox, Safari и гибридных мобильных приложениях (Cordova и Ionic на iOS / Android)

демонстрация

Джон Доэрти
источник
2
Здорово, дружище !!
Джефф Т.
1
Обезьяна этого решения исправляет объект window.CustomEvent несколько бессистемно, неполно и нестандартно. Он не создает свойства только для чтения как доступные только для чтения, а скорее для чтения и записи. В частности, отсутствуют returnValue, type, timeStamp и isTrusted. Он не решает проблему перетаскивания, жестов, увеличения или уменьшения масштабирования или пропадания мультитач при длительном нажатии, а также не решает проблему большого количества устройств и / или платформ, которые по умолчанию используют длительное нажатие для выделения текста даже при 500 мс. В библиотеке отсутствуют все тестовые примеры для этих условий.
4
Это открытый исходный код, не стесняйтесь вносить свой вклад в проект :)
Джон Доэрти
@JohnDoherty отлично! но можем ли мы по-прежнему использовать onClick с тем же элементом?
Devashish 09
2
Вы все равно должны получать событие «onclick» до тех пор, пока долгое нажатие не
Джон Доэрти
15

Хотя это выглядит достаточно простым, чтобы реализовать его самостоятельно с тайм-аутом и парой обработчиков событий мыши, он становится немного сложнее, если вы рассматриваете такие случаи, как нажатие-перетаскивание-отпускание, поддерживающее как нажатие, так и длительное нажатие на один и тот же элемент и работать с сенсорными устройствами, такими как iPad. В итоге я использовал плагин jQuery longclick ( Github ), который позаботился обо всем этом за меня. Если вам нужно поддерживать только устройства с сенсорным экраном, например мобильные телефоны, вы также можете попробовать событие Taphold jQuery Mobile .

ʇsәɹoɈ
источник
Ссылка Github работает, но проект не обновлялся с 2010 года и не работает с текущими версиями jquery. Однако замена handle.apply на dispatch.apply в исходном коде исправляет это.
arlomedia 04
11

Плагин jQuery. Просто поставь $(expression).longClick(function() { <your code here> });. Второй параметр - длительность удержания; тайм-аут по умолчанию - 500 мс.

(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
источник
это не сохраняется в вызове.
Champ
привет, братан, можем ли мы использовать это в качестве
основного
6

Для кросс-платформенных разработчиков (Примечание. Все ответы, приведенные до сих пор, не будут работать на iOS) :

Mouseup / down, похоже, нормально работает на Android, но не на всех устройствах, например (samsung tab4). На iOS вообще не работало .

Дальнейшие исследования показывают, что это связано с тем, что элемент имеет выделение, а собственное увеличение прерывает слушателя.

Этот прослушиватель событий позволяет открывать эскизное изображение в модальном режиме начальной загрузки, если пользователь удерживает изображение в течение 500 мс.

Он использует класс отзывчивого изображения, поэтому показывает увеличенную версию изображения. Этот фрагмент кода был полностью протестирован (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
источник
хорошее решение для iOS
eric xu
как мне предотвратить прикосновения, которые начинаются на миниатюре, но, скажем, заканчиваются прокруткой. Другими словами, не касание начала / конца на месте, а прикосновение, которое началось с элемента с помощью обработчика, но закончилось прокруткой
Акин Хван
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

малина
источник
2
В этом коде longclick не запускается в конце 500 мс. Пользователь может умереть щелчком мыши :). Длинный щелчок запускается только в том случае, если пользователь перестанет нажимать кнопку.
джедаи
Будет ли это охватывать случай, когда пользователь начал прокрутку вместо того, чтобы закончить долгое нажатие в том же месте?
Акин Хван
@AkinHwan Нет, это сработает, только если щелкнуть мышью над тем же элементом.
малина
4

Ответ Diodeus потрясающий, но он не позволяет вам добавить функцию onClick, он никогда не запустит функцию удержания, если вы поместите onclick. И ответ Razzak почти идеален, но он запускает функцию удержания только при наведении курсора мыши, и, как правило, функция запускается, даже если пользователь продолжает удерживать.

Итак, я присоединился к обоим и сделал следующее:

$(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
источник
что, если пользователь начал прокрутку после mousedown и не собирался делать долгое нажатие
Акин Хван
4

Для современных мобильных браузеров:

document.addEventListener('contextmenu', callback);

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

Кори Нанн
источник
Или для JQuery используйте $ (selector) .bind ('contextmenu', function () {})
dfmiller
прекратить использование bind()jquery 1.7+ = on()и unbind()=off()
dbinott
2

Вы можете установить тайм-аут для этого элемента при нажатии мыши и очистить его при поднятии мыши:

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

При этом каждый элемент получает свой тайм-аут.

гумбо
источник
1
$(this).mouseup(function(){});не удаляет обработчик событий, а добавляет еще один. .unbindВместо этого используйте .
Матти Вирккунен
следует использовать off()сейчас вместо отмены привязки.
dbinott
1

Вы можете использовать taphold jquery-mobile. Включите jquery-mobile.js, и следующий код будет работать нормально

$(document).on("pagecreate","#pagename",function(){
  $("p").on("taphold",function(){
   $(this).hide(); //your code
  });    
});
Prashant_M
источник
Это должен быть принятый ответ, поскольку jquery-mobile обеспечивает хорошую стабильную структуру
pasx
1

Наиболее элегантным и чистым является плагин jQuery: https://github.com/untill/jquery.longclick/ , также доступный как packacke: https://www.npmjs.com/package/jquery.longclick .

Короче, вы используете это так:

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

Преимущество этого плагина в том, что, в отличие от некоторых других ответов здесь, события щелчка все еще возможны. Также обратите внимание, что перед курсором мыши происходит долгий щелчок, как и долгое нажатие на устройстве. Итак, это особенность.

недо
источник
0

Для меня это работает с этим кодом (с 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
источник
0

Вы можете проверить время, чтобы определить нажатие или длительное нажатие [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
источник
0

как это?

doc.addEeventListener("touchstart", function(){
    // your code ...
}, false);    
翁 沈 顺
источник
0

Вы можете использовать jqueryсобытия Touch. ( см. здесь )

  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 );
  });
Иртеза Асад
источник
0

Мне нужно было что-то для событий длительного нажатия на клавиатуре, поэтому я написал это.

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
источник
0

Думаю, это может вам помочь:

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
источник