Javascript 在触摸屏上处理鼠标和触摸事件
我正在编写web应用程序,它应该支持鼠标和触摸交互。 对于测试,我使用带有Windows7的触摸屏设备。我尝试在最新的Firefox和Chrome canary中嗅探触摸事件,结果如下: 触控Firefox触发触控和相应的鼠标事件。 Chrome启动了Javascript 在触摸屏上处理鼠标和触摸事件,javascript,google-chrome,firefox,touch,touchscreen,Javascript,Google Chrome,Firefox,Touch,Touchscreen,我正在编写web应用程序,它应该支持鼠标和触摸交互。 对于测试,我使用带有Windows7的触摸屏设备。我尝试在最新的Firefox和Chrome canary中嗅探触摸事件,结果如下: 触控Firefox触发触控和相应的鼠标事件。 Chrome启动了touchstart/mousedown,touchend/mouseup对,但mousemove以非常奇怪的方式启动:在touchmove时启动了一/两次 所有鼠标事件都将一如既往地处理 在现代触摸屏上,有没有办法同时处理鼠标和触摸屏?如果Fir
touchstart/mousedown
,touchend/mouseup
对,但mousemove
以非常奇怪的方式启动:在touchmove
时启动了一/两次
所有鼠标事件都将一如既往地处理
在现代触摸屏上,有没有办法同时处理鼠标和触摸屏?如果Firefox触发了一对触摸和鼠标事件,那么Chrome中的touchmove
和mousemove
会发生什么?我应该将所有鼠标事件转换为触摸还是反之?我希望找到创建响应界面的正确方法。您应该检查触摸界面的可用性,并据此绑定事件
您可以这样做:
(function () {
if ('ontouchstart' in window) {
window.Evt = {
PUSH : 'touchstart',
MOVE : 'touchmove',
RELEASE : 'touchend'
};
} else {
window.Evt = {
PUSH : 'mousedown',
MOVE : 'mousemove',
RELEASE : 'mouseup'
};
}
}());
// and then...
document.getElementById('mydiv').addEventListener(Evt.PUSH, myStartDragHandler, false);
若你们想同时处理这两个事件,而浏览器不能很好地将触摸事件转换成鼠标事件,你们可以捕捉触摸事件并停止它们——那个么相应的鼠标事件不应该被浏览器触发(你们不会有两个事件),你们可以自己作为鼠标事件触发,或者直接处理它
var mydiv = document.getElementsById('mydiv');
mydiv.addEventListener('mousemove', myMoveHandler, false);
mydiv.addEventListener('touchmove', function (e) {
// stop touch event
e.stopPropagation();
e.preventDefault();
// translate to mouse event
var clkEvt = document.createEvent('MouseEvent');
clkEvt.initMouseEvent('mousemove', true, true, window, e.detail,
e.touches[0].screenX, e.touches[0].screenY,
e.touches[0].clientX, e.touches[0].clientY,
false, false, false, false,
0, null);
mydiv.dispatchEvent(clkEvt);
// or just handle touch event
myMoveHandler(e);
}, false);
你无法预先预测要监听哪些事件(例如,据你所知,在你的页面加载后,USB触摸屏可能会被插入)
相反,您应该始终同时侦听触摸事件和鼠标事件,但对您处理的触摸事件调用preventDefault(),以防止触发(现在是冗余的)鼠标事件。有关详细信息,请参阅。我一直在使用这个jQuery助手绑定触摸和单击事件
(function ($) {
$.fn.tclick = function (onclick) {
this.bind("touchstart", function (e) { onclick.call(this, e); e.stopPropagation(); e.preventDefault(); });
this.bind("click", function (e) { onclick.call(this, e); }); //substitute mousedown event for exact same result as touchstart
return this;
};
})(jQuery);
MouseeEvents和TouchEvents在技术上并不提供完全相同的功能,但在大多数情况下,它们可以互换使用。这种解决方案并不偏向于一种,因为用户可能同时拥有鼠标和触摸屏。相反,它允许用户使用他们想要的输入设备,只要他们在更改输入之前至少等待五秒钟。此解决方案在轻触屏幕时忽略触摸屏设备上的鼠标指针模拟
var lastEvent=3;
var MOUSE_EVENT=1;
var TOUCH_事件=2;
元素。addEventListener('touchstart',函数(事件)
{
if(lastEvent==鼠标事件)
{
var time=Date.now()-eventTime;
如果(时间>5000)
{
eventTime=Date.now();
lastEvent=触摸事件;
交互启动(事件);
}
}
其他的
{
lastEvent=触摸事件;
eventTime=Date.now();
交互启动(事件);
}
}) ;
元素。addEventListener('mousedown',函数(事件)
{
如果(lastEvent==触摸事件)
{
var time=Date.now()-eventTime;
如果(时间>5000)
{
eventTime=Date.now();
lastEvent=鼠标事件;
交互启动(事件);
}
}
其他的
{
lastEvent=鼠标事件;
eventTime=Date.now();
交互启动(事件);
}
}) ;
函数interactionStart(事件)//在此处处理交互(触摸或单击)。
{…}
我发现了这个线程,因为我有一个类似的更复杂的问题:
假设我们创建了一个支持js的可滚动区域,其中包含下一个/上一个箭头,我们不仅希望对触摸和鼠标事件做出响应,还希望在用户继续按下屏幕或按住鼠标的同时重复触发它们
重复事件会使我的下一个按钮前进2个位置,而不是一个
在闭包的帮助下,一切似乎都是可能的:
(1)首先为变量隔离创建一个自调用函数:
(function(myScroll, $, window, document, undefined){
...
}(window.myScroll = window.myScroll || {}, jQuery, window, document));
/*
* Primary events for handlers that respond to more than one event and devices
* that produce more than one, like touch devices.
* The first event in browser's queue hinders all subsequent for the specific
* key intended to be used by a handler.
* Every key points to an object '{primary: <event type>}'.
*/
var eventLock = {};
// Process ids based on keys.
var pids = {};
// Some defaults
var defaults = {
pressDelay: 100 // ms between successive calls for continuous press by mouse or touch
}
function getEventLock(evt, key){
if(typeof(eventLock[key]) == 'undefined'){
eventLock[key] = {};
eventLock[key].primary = evt.type;
return true;
}
if(evt.type == eventLock[key].primary)
return true;
else
return false;
}
function primaryEventLock(evt, key){
eventLock[key].primary = evt.type;
}
function init(){
$('sth').off('mousedown touchstart', previousStart).on('mousedown touchstart', previousStart);
$('sth').off('mouseup touchend', previousEnd).on('mouseup touchend', previousEnd);
// similar for 'next*' handlers
}
function previousStart(evt){
// 'race' condition/repetition between 'mousedown' and 'touchstart'
if(!getEventLock(evt, 'previous'))
return;
// a. !!!you have to implement this!!!
previous(evt.target);
// b. emulate successive events of this type
pids.previous = setTimeout(closure, defaults.pressDelay);
// internal function repeats steps (a), (b)
function closure(){
previous(evt.target);
primaryEventLock(evt, 'previous');
pids.previous = setTimeout(closure, defaults.pressDelay);
}
};
function previousEnd(evt){
clearTimeout(pids.previous);
};
myScroll.init = init;
(2)然后,从setTimeout()
:
(function(myScroll, $, window, document, undefined){
...
}(window.myScroll = window.myScroll || {}, jQuery, window, document));
/*
* Primary events for handlers that respond to more than one event and devices
* that produce more than one, like touch devices.
* The first event in browser's queue hinders all subsequent for the specific
* key intended to be used by a handler.
* Every key points to an object '{primary: <event type>}'.
*/
var eventLock = {};
// Process ids based on keys.
var pids = {};
// Some defaults
var defaults = {
pressDelay: 100 // ms between successive calls for continuous press by mouse or touch
}
function getEventLock(evt, key){
if(typeof(eventLock[key]) == 'undefined'){
eventLock[key] = {};
eventLock[key].primary = evt.type;
return true;
}
if(evt.type == eventLock[key].primary)
return true;
else
return false;
}
function primaryEventLock(evt, key){
eventLock[key].primary = evt.type;
}
function init(){
$('sth').off('mousedown touchstart', previousStart).on('mousedown touchstart', previousStart);
$('sth').off('mouseup touchend', previousEnd).on('mouseup touchend', previousEnd);
// similar for 'next*' handlers
}
function previousStart(evt){
// 'race' condition/repetition between 'mousedown' and 'touchstart'
if(!getEventLock(evt, 'previous'))
return;
// a. !!!you have to implement this!!!
previous(evt.target);
// b. emulate successive events of this type
pids.previous = setTimeout(closure, defaults.pressDelay);
// internal function repeats steps (a), (b)
function closure(){
previous(evt.target);
primaryEventLock(evt, 'previous');
pids.previous = setTimeout(closure, defaults.pressDelay);
}
};
function previousEnd(evt){
clearTimeout(pids.previous);
};
myScroll.init = init;
(4)附加事件处理程序:
(function(myScroll, $, window, document, undefined){
...
}(window.myScroll = window.myScroll || {}, jQuery, window, document));
/*
* Primary events for handlers that respond to more than one event and devices
* that produce more than one, like touch devices.
* The first event in browser's queue hinders all subsequent for the specific
* key intended to be used by a handler.
* Every key points to an object '{primary: <event type>}'.
*/
var eventLock = {};
// Process ids based on keys.
var pids = {};
// Some defaults
var defaults = {
pressDelay: 100 // ms between successive calls for continuous press by mouse or touch
}
function getEventLock(evt, key){
if(typeof(eventLock[key]) == 'undefined'){
eventLock[key] = {};
eventLock[key].primary = evt.type;
return true;
}
if(evt.type == eventLock[key].primary)
return true;
else
return false;
}
function primaryEventLock(evt, key){
eventLock[key].primary = evt.type;
}
function init(){
$('sth').off('mousedown touchstart', previousStart).on('mousedown touchstart', previousStart);
$('sth').off('mouseup touchend', previousEnd).on('mouseup touchend', previousEnd);
// similar for 'next*' handlers
}
function previousStart(evt){
// 'race' condition/repetition between 'mousedown' and 'touchstart'
if(!getEventLock(evt, 'previous'))
return;
// a. !!!you have to implement this!!!
previous(evt.target);
// b. emulate successive events of this type
pids.previous = setTimeout(closure, defaults.pressDelay);
// internal function repeats steps (a), (b)
function closure(){
previous(evt.target);
primaryEventLock(evt, 'previous');
pids.previous = setTimeout(closure, defaults.pressDelay);
}
};
function previousEnd(evt){
clearTimeout(pids.previous);
};
myScroll.init = init;
触发事件mousedown
和touchstart
将对支持这两种功能的设备上的处理程序产生双重调用(可能首先触发触摸)。这同样适用于mouseup
和touchend
我们知道输入设备(实际上是整个图形环境)会按顺序生成事件,因此我们不关心先触发哪个事件,只要在privateeventLock.next.primary
和eventLock.previous.primary
中为从处理程序捕获的第一个事件设置了next*()
和上一代*()
该键是事件类型,因此第二个、第三个等事件始终是失败者,它们不会借助锁函数eventLock()
和primaryEventLock()
获得锁
(5)在事件处理程序的定义中可以看到上述内容:
(function(myScroll, $, window, document, undefined){
...
}(window.myScroll = window.myScroll || {}, jQuery, window, document));
/*
* Primary events for handlers that respond to more than one event and devices
* that produce more than one, like touch devices.
* The first event in browser's queue hinders all subsequent for the specific
* key intended to be used by a handler.
* Every key points to an object '{primary: <event type>}'.
*/
var eventLock = {};
// Process ids based on keys.
var pids = {};
// Some defaults
var defaults = {
pressDelay: 100 // ms between successive calls for continuous press by mouse or touch
}
function getEventLock(evt, key){
if(typeof(eventLock[key]) == 'undefined'){
eventLock[key] = {};
eventLock[key].primary = evt.type;
return true;
}
if(evt.type == eventLock[key].primary)
return true;
else
return false;
}
function primaryEventLock(evt, key){
eventLock[key].primary = evt.type;
}
function init(){
$('sth').off('mousedown touchstart', previousStart).on('mousedown touchstart', previousStart);
$('sth').off('mouseup touchend', previousEnd).on('mouseup touchend', previousEnd);
// similar for 'next*' handlers
}
function previousStart(evt){
// 'race' condition/repetition between 'mousedown' and 'touchstart'
if(!getEventLock(evt, 'previous'))
return;
// a. !!!you have to implement this!!!
previous(evt.target);
// b. emulate successive events of this type
pids.previous = setTimeout(closure, defaults.pressDelay);
// internal function repeats steps (a), (b)
function closure(){
previous(evt.target);
primaryEventLock(evt, 'previous');
pids.previous = setTimeout(closure, defaults.pressDelay);
}
};
function previousEnd(evt){
clearTimeout(pids.previous);
};
myScroll.init = init;
与nextStart
和nextEnd
类似
这个想法是,在第一次(触摸或鼠标)之后出现的任何人都不会在函数eventLock(evt,key)
的帮助下获得锁,而是停在那里
打开此锁的唯一方法是在步骤(4):previousEnd
和nextEnd
中启动事件处理程序*End()
我还处理了一个非常聪明的方式在会话中间附加的触摸设备问题:我注意到一个连续的按压时间比