如何使用适用于 android 和 iphone 的 javascript 检测长触摸压力? 原生 javascript 或 jquery...
我想要听起来像这样的东西:
<input type='button' onLongTouch='myFunc();' />
使用 Touch End 来检测长触摸的问题是,如果您希望事件在一段时间后触发,它将无法工作。最好在触摸开始时使用计时器,并在触摸结束时清除事件计时器。可以使用以下模式:
var onlongtouch;
var timer;
var touchduration = 500; //length of time we want the user to touch before we do something
touchstart() {
timer = setTimeout(onlongtouch, touchduration);
}
touchend() {
//stops short touches from firing the event
if (timer)
clearTimeout(timer); // clearTimeout, not cleartimeout..
}
onlongtouch = function() { //do something };
这是 Joshua 答案的扩展版本,因为他的代码运行良好,直到用户不执行多点触控(您可以用两根手指点击屏幕,功能将被触发两次,4 根手指 - 4 次)。 经过一些额外的测试场景后,我什至触发了非常频繁地触摸并在每次点击后接收执行的功能的可能性。
我添加了名为“lockTimer”的变量,它应该在用户触发“touchend”之前锁定任何其他 touchstart。
var onlongtouch;
var timer;
var touchduration = 800; //length of time we want the user to touch before we do something
function touchstart(e) {
e.preventDefault();
if (!timer) {
timer = setTimeout(onlongtouch, touchduration);
}
}
function touchend() {
//stops short touches from firing the event
if (timer) {
clearTimeout(timer);
timer = null;
}
}
onlongtouch = function() {
timer = null;
document.getElementById('ping').innerText+='ping\n';
};
document.addEventListener("DOMContentLoaded", function(event) {
window.addEventListener("touchstart", touchstart, false);
window.addEventListener("touchend", touchend, false);
});
<div id="ping"></div>
此处发布的解决方案忽略了用户需要触摸屏幕才能启动滚动的事实。如果用户不尝试滚动,我们只希望长按行为。
function onLongPress(element, callback) {
let timer;
element.addEventListener('touchstart', () => {
timer = setTimeout(() => {
timer = null;
callback();
}, 500);
});
function cancel() {
clearTimeout(timer);
}
element.addEventListener('touchend', cancel);
element.addEventListener('touchmove', cancel);
}
然后:
onLongPress(element, () => {
console.log('Long pressed', element);
});
我在我的 Android 应用程序中这样做了:
注册事件监听器:
var touchStartTimeStamp = 0;
var touchEndTimeStamp = 0;
window.addEventListener('touchstart', onTouchStart,false);
window.addEventListener('touchend', onTouchEnd,false);
新增功能:
var timer;
function onTouchStart(e) {
touchStartTimeStamp = e.timeStamp;
}
function onTouchEnd(e) {
touchEndTimeStamp = e.timeStamp;
console.log(touchEndTimeStamp - touchStartTimeStamp);// in miliseconds
}
检查时差并完成我的工作
我希望这会有所帮助。
基于@djanowski 的解决方案来处理触摸滚动。 这也应该防止长按上下文菜单和选择。
function onLongPress(element, callback) {
var timeoutId;
element.addEventListener('touchstart', function(e) {
timeoutId = setTimeout(function() {
timeoutId = null;
e.stopPropagation();
callback(e.target);
}, 500);
});
element.addEventListener('contextmenu', function(e) {
e.preventDefault();
});
element.addEventListener('touchend', function () {
if (timeoutId) clearTimeout(timeoutId);
});
element.addEventListener('touchmove', function () {
if (timeoutId) clearTimeout(timeoutId);
});
}
onLongPress(document.getElementById('kitty1'), function(element) {
alert('Meow from ' + element.outerHTML );
});
onLongPress(document.getElementById('kitty2'), function(element) {
alert('Meow from ' + element.outerHTML );
});
img {
max-width: 100%;
-webkit-user-select: none; /* Safari */
-ms-user-select: none; /* IE 10 and IE 11 */
user-select: none; /* Standard syntax */
}
<p>Long press on kitty! Kitty should meow on 500ms long press but not scroll</p>
<img id="kitty1" src="http://placekitten.com/300/400" />
<img id="kitty2" src="http://placekitten.com/300/300" />
我们可以计算出触摸开始和触摸结束的时间差。如果计算出的时间差超过触摸持续时间,则我们使用函数名称 taphold。
var touchduration = 300;
var timerInterval;
function timer(interval) {
interval--;
if (interval >= 0) {
timerInterval = setTimeout(function() {
timer(interval);
});
} else {
taphold();
}
}
function touchstart() {
timer(touchduration);
}
function touchend() {
clearTimeout(timerInterval);
}
function taphold(){
alert("taphold");
}
document.getElementById("xyz").addEventListener('touchstart',touchstart);
document.getElementById("xyz").addEventListener('touchend',touchend);
对于跨平台开发者:
鼠标向上/向下似乎在 android 上工作正常 - 但并非所有设备即(三星 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)
});
这个基于@Joshua的更好的解决方案,有时需要直接在事件内部调用代码(某些Web API需要用户操作来触发某些内容),对于这种情况,您可以使用此修改:
var longtouch;
var timer;
//length of time we want the user to touch before we do something
var touchduration = 500;
function touchstart() {
longtouch = false;
timer = setTimeout(function() {
longtouch = true;
timer = null
}, touchduration);
}
function touchend() {
if (timer) {
clearTimeout(timer);
timer = null;
}
if (longtouch) {
// your long acction inside event
longtouch = false;
}
}
在 setTimeout 中将标志设置为 true,并在 touchend 内检查它是否已设置。
这适用于我的用例,即想要在触摸屏幕时执行某些功能。
let triggerInterval = 200; // in milliseconds
let timerId;
function touchstart(e) {
// e.preventDefault();
timerId = setInterval(yourFunction, triggerInterval);
}
function touchend(e) {
clearInterval(timerId);
}
function yourFunction() {
// perform your logic
}
document.addEventListener("touchstart", touchstart);
document.addEventListener("touchend", touchend);
注意:- triggerInterval 中的值越小,执行 yourFunction() 的速度就越快。
完成程序后,您可以删除相应的事件监听器:
document.removeEventListener("touchstart", touchstart);
document.removeEventListener("touchend", touchend);
我采纳了此处答案中提出的很多想法,并将它们组合起来形成以下辅助函数,我将其用于长按功能。
我已经在 Windows 和 Android 上的 Chrome 中对其进行了相当彻底的测试,它可以一致地处理鼠标和触摸交互。
const addLongPressListener = ({ element, callback, delay = 500, preventClick = true }) => {
var longPressTimeout;
var longPressed = false;
const longPressStart = (e) => {
longPressTimeout = setTimeout(() => {
longPressed = true;
e.stopPropagation();
callback && typeof callback === 'function' && callback(e);
}, delay);
};
const longClickCancel = (e) => {
longPressTimeout && clearTimeout(longPressTimeout);
};
const longTouchCancel = (e) => {
longPressTimeout && clearTimeout(longPressTimeout);
longPressed = false;
};
element.addEventListener('touchstart', (e) => longPressStart(e), false);
element.addEventListener('mousedown', (e) => longPressStart(e), false);
element.addEventListener('contextmenu', (e) => e.preventDefault(), false);
element.addEventListener(
'click',
(e) => {
if (preventClick && longPressed) e.preventDefault();
longPressed = false;
},
false
);
element.addEventListener('touchend', (e) => longTouchCancel(e), false);
element.addEventListener('touchmove', (e) => longTouchCancel(e), false);
element.addEventListener('mouseup', (e) => longClickCancel(e), false);
element.addEventListener('mousemove', (e) => longClickCancel(e), false);
};
在我可以修改 Element 原型的项目中,我还添加以下内容以使使用侦听器更像使用普通的
addEventListener
。
Object.defineProperty(Element.prototype, 'addLongPressListener', {
value: function (callback, params) {
addLongPressListener({ element: this, callback, ...params });
},
enumerable: false,
});
添加 Element 原型后,使用监听器看起来像这样:
let target = document.getElementById('target');
target.addLongPressListener((e) => {
console.log('Long Press');
});
当使用可选参数来控制延迟时间以及是否阻止长按时的正常点击事件时,它看起来像这样:
let target = document.getElementById('target');
target.addLongPressListener(
(e) => {
console.log('Extra Long Press');
},
{ delay: 2000, preventClick: false }
);
最后,这是可以使用的完整工作代码片段:
const addLongPressListener = ({
element,
callback,
delay = 500,
preventClick = true
}) => {
var longPressTimeout;
var longPressed = false;
const longPressStart = (e) => {
longPressTimeout = setTimeout(() => {
longPressed = true;
e.stopPropagation();
callback && typeof callback === 'function' && callback(e);
}, delay);
};
const longClickCancel = (e) => {
longPressTimeout && clearTimeout(longPressTimeout);
};
const longTouchCancel = (e) => {
longPressTimeout && clearTimeout(longPressTimeout);
longPressed = false;
};
element.addEventListener('touchstart', (e) => longPressStart(e), false);
element.addEventListener('mousedown', (e) => longPressStart(e), false);
element.addEventListener('contextmenu', (e) => e.preventDefault(), false);
element.addEventListener(
'click',
(e) => {
if (preventClick && longPressed) e.preventDefault();
longPressed = false;
},
false
);
element.addEventListener('touchend', (e) => longTouchCancel(e), false);
element.addEventListener('touchmove', (e) => longTouchCancel(e), false);
element.addEventListener('mouseup', (e) => longClickCancel(e), false);
element.addEventListener('mousemove', (e) => longClickCancel(e), false);
};
Object.defineProperty(Element.prototype, 'addLongPressListener', {
value: function(callback, params) {
addLongPressListener({
element: this,
callback,
...params
});
},
enumerable: false,
});
let normalTarget = document.getElementById('normal_target');
normalTarget.addLongPressListener((e) => {
console.log('Long Press');
});
let longTarget = document.getElementById('long_target');
longTarget.addLongPressListener(
(e) => {
console.log('Extra Long Press');
}, {
delay: 2000,
preventClick: false
}
);
body {
margin: 0;
}
.container {
width: 100vw;
height: 100vh;
display: flex;
justify-content: space-evenly;
align-items: start;
background-color: #252627;
}
.button {
padding: 1rem;
margin: 1rem;
border: 2px solid #5f6368;
border-radius: 1rem;
background-color: #be32ff;
color: #ffffff;
font-size: 24px;
font-weight: bold;
Font-family: Roboto, Sans-serif;
cursor: pointer;
}
<div class='container'>
<span id='normal_target' class='button'>Normal Long Press</span>
<span id='long_target' class='button'>Extra Long Press</span>
<div>
适用于所有浏览器的长按事件
(function (a) {
function n(b) { a.each("touchstart touchmove touchend touchcancel".split(/ /), function (d, e) { b.addEventListener(e, function () { a(b).trigger(e) }, false) }); return a(b) } function j(b) { function d() { a(e).data(h, true); b.type = f; jQuery.event.handle.apply(e, o) } if (!a(this).data(g)) { var e = this, o = arguments; a(this).data(h, false).data(g, setTimeout(d, a(this).data(i) || a.longclick.duration)) } } function k() { a(this).data(g, clearTimeout(a(this).data(g)) || null) } function l(b) {
if (a(this).data(h)) return b.stopImmediatePropagation() ||
false
} var p = a.fn.click; a.fn.click = function (b, d) { if (!d) return p.apply(this, arguments); return a(this).data(i, b || null).bind(f, d) }; a.fn.longclick = function () { var b = [].splice.call(arguments, 0), d = b.pop(); b = b.pop(); var e = a(this).data(i, b || null); return d ? e.click(b, d) : e.trigger(f) }; a.longclick = { duration: 500 }; a.event.special.longclick = {
setup: function () {
/iphone|ipad|ipod/i.test(navigator.userAgent) ? n(this).bind(q, j).bind([r, s, t].join(" "), k).bind(m, l).css({ WebkitUserSelect: "none" }) : a(this).bind(u, j).bind([v,
w, x, y].join(" "), k).bind(m, l)
}, teardown: function () { a(this).unbind(c) }
}; var f = "longclick", c = "." + f, u = "mousedown" + c, m = "click" + c, v = "mousemove" + c, w = "mouseup" + c, x = "mouseout" + c, y = "contextmenu" + c, q = "touchstart" + c, r = "touchend" + c, s = "touchmove" + c, t = "touchcancel" + c, i = "duration" + c, g = "timer" + c, h = "fired" + c
})(jQuery);
绑定长按事件与时间间隔
$('element').longclick(250, longClickHandler);
长按触摸设备时会触发以下功能
function longClickHandler() {
alter('Long tap Fired');
}