检测浏览器没有鼠标并且仅是触摸式


149

我正在开发一个Web应用程序(不是一个包含有趣文本页面的网站),其触摸(您的手指在单击时隐藏屏幕)和鼠标(很大程度上取决于悬停预览)的界面非常不同。如何检测到我的用户没有鼠标向他展示正确的界面?我计划为使用鼠标和触摸的人(例如某些笔记本电脑)留下一个开关。

浏览器中的触摸事件功能实际上并不意味着用户正在使用触摸设备(例如,Modernizr不会对其进行裁剪)。如果设备具有鼠标,则正确回答该问题的代码应返回false,否则返回true。对于具有鼠标和触摸功能的设备,它应该返回false(不仅限于触摸)

附带说明一下,我的触摸界面也可能适用于仅键盘的设备,因此更多是我想检测不到的鼠标。

为了使需求更加清楚,这是我要实现的API:

// Level 1


// The current answers provide a way to do that.
hasTouch();

// Returns true if a mouse is expected.
// Note: as explained by the OP, this is not !hasTouch()
// I don't think we have this in the answers already, that why I offer a bounty
hasMouse();

// Level 2 (I don't think it's possible, but maybe I'm wrong, so why not asking)

// callback is called when the result of "hasTouch()" changes.
listenHasTouchChanges(callback);

// callback is called when the result of "hasMouse()" changes.
listenHasMouseChanges(callback);


我想,如果您希望一个应用程序既适用于台式机又适用于移动/触摸,但每个应用程序都有不同的行为,则需要重新考虑设计。我认为目前您所追求的实际上是不可能的,因为在Google上快速搜索“ javascript检测鼠标”会在quirksmode.org上显示一个适度有用的帖子,用于检测鼠标的各种状态(点击,位置,等等),但会根据鼠标是否实际存在归零。
davethegr8 '02

24
也许是因为Google在这里没有要求我没有帮助。
nraynaud 2012年

2
您是否尝试过jquery中的document mouseenter?$(document).mouseenter(function(e){alert(“ mouse”);});
Parag Gajjar'2

4
在考虑了将近十二种有前途的途径之后,在几分钟之内就拒绝了每一个途径之后,这个问题使我非常兴奋。
约旦·格雷

Answers:


65

主要的麻烦是您具有以下不同类别的设备/用例:

  1. 鼠标和键盘(桌面)
  2. 仅触摸(手机/平板电脑)
  3. 鼠标,键盘和触摸(触摸笔记本电脑)
  4. 触摸和键盘(平板电脑上的蓝牙键盘)
  5. 仅鼠标(禁用的用户/浏览首选项)
  6. 仅键盘(禁用的用户/浏览首选项)
  7. 触摸和鼠标(例如,Galaxy Note 2笔的悬停事件)

更糟糕的是,一个人可以从其中一些类别过渡到其他类别(插入鼠标,连接键盘),或者用户可能会出现在普通笔记本电脑上,直到他们伸出手并触摸屏幕为止。

您假设浏览器中存在事件构造函数不是前进的好方法(并且有些不一致),这是正确的。此外,除非您要跟踪一个非常特定的事件,或者仅试图排除上面的几个类,否则使用事件本身并不是充分的证明。

例如,假设您发现用户发出了一次真正的鼠标移动(不是触摸事件中的错误鼠标移动,请参见http://www.html5rocks.com/en/mobile/touchandmouse/)。

那呢

您启用悬停样式吗?您添加更多按钮?

无论哪种方式,您都需要花费更多的时间来准备酒杯,因为您必须等待事件触发。

但是,当贵族用户决定要拔出鼠标并进行全面触摸时,会发生什么情况?您是否等待他触摸您现在拥挤的界面,然后在他努力确定现在拥挤的UI之后立即对其进行更改?

以项目符号的形式在https://github.com/Modernizr/Modernizr/issues/869#issuecomment-15264101上引用stucox

  • 我们要检测鼠标的存在
  • 在事件触发之前,AE可能无法检测到
  • 因此,我们正在检测的是此会话中是否使用过鼠标-不会立即从页面加载中获取
  • 我们可能也无法检测到没有鼠标,只有在定义为true之前它才是未定义的(我认为这比将其设置为false直到被证明还有意义)
  • 而且我们可能无法检测到鼠标是否在会话中断开连接–与仅放弃鼠标的用户是无法区分的

顺便说一句:浏览器不知道用户何时插入鼠标/连接到键盘,但是没有将其暴露给JavaScript。

这应该导致您以下:

跟踪给定用户的当前功能是复杂,不可靠且值得怀疑的

不过,渐进增强的想法在这里适用得很好。无论用户的环境如何,都可以构建平稳运行的体验。然后基于浏览器功能/媒体查询进行假设,以添加在假设上下文中相对的功能。鼠标的存在只是不同设备上的不同用户访问您的网站的多种方式之一。在其内核中创建具有优点的东西,不必太担心人们如何单击按钮。


3
好答案。希望用户始终有一个屏幕!我认为建立一个与用户当前交互模式相对应的界面是有意义的。在触摸式笔记本电脑上,:hover当用户从鼠标切换到触摸屏时,调整应用程序(即元素和类似的东西)很有意义。用户当前似乎不太可能在完全相同的时间使用鼠标+触摸(我的意思是,这就像是将2只鼠标连接到同一台计算机一样哈哈哈)
Sebastien Lorber

@SebastienLorber -恨打破它给你,但用户并不一定总是有一个屏幕。(是否可以使用JavaScript来检测屏幕阅读器是否在用户计算机上运行?
ashleedawg

57

如何监听文档上的mousemove事件。然后,直到您听到该事件,您都假定设备仅是触摸屏或键盘。

var mouseDetected = false;
function onMouseMove(e) {
  unlisten('mousemove', onMouseMove, false);
  mouseDetected = true;
  // initializeMouseBehavior();
}
listen('mousemove', onMouseMove, false);

(在哪里listenunlisten委托给addEventListenerattachEvent酌情委托。)

希望这不会导致过多的视觉混乱,如果您需要基于模式的大量重新布局,那会很烂...


2
这是个好主意,但不幸的是,当应用程序的UI取决于鼠标是否可用时,响应的延迟将使其无法使用。尤其是如果应用程序经过了格式化,则鼠标事件只会在以下情况下命中它:鼠标移动在IFRAME本身..
乔恩Gjengset

7
如果应用程序以启动屏幕和“继续”按钮开始,则可能会起作用。如果鼠标在第一个mousedown事件之前移动,则您有鼠标。仅当按钮直接加载在鼠标下方并且用户的手非常稳固(即使移动1个像素时也应拾取)时,它才会失败。
SpliFF'2

49
不错的主意,但似乎无法在我们的测试中使用。iPad触发此事件。
杰夫·阿特伍德

3
@JeffAtwood在您的案例中您最终做了什么?
Michael Haren

2
iPad肯定会在mousedown事件之前触发mousemove事件。我发现mousedown计数> 0和mousedown计数== mousemove计数是检测没有鼠标的好方法。我无法用真正的鼠标复制它。
彼得·伍斯特

36

截至2018年,有一种很好且可靠的方法来检测浏览器是否具有鼠标(或类似的输入设备):CSS4媒体交互功能现在几乎由任何现代浏览器(IE 11和特殊的移动浏览器除外)都支持。

W3C:

指针媒体功能用于查询指针设备(例如鼠标)的存在和准确性。

请参阅以下选项:

    /* The primary input mechanism of the device includes a 
pointing device of limited accuracy. */
    @media (pointer: coarse) { ... }

    /* The primary input mechanism of the device 
includes an accurate pointing device. */
    @media (pointer: fine) { ... }

    /* The primary input mechanism of the 
device does not include a pointing device. */
    @media (pointer: none) { ... }

    /* Primary input mechanism system can 
       hover over elements with ease */
    @media (hover: hover) { ... }

    /* Primary input mechanism cannot hover 
       at all or cannot conveniently hover 
       (e.g., many mobile devices emulate hovering
       when the user performs an inconvenient long tap), 
       or there is no primary pointing input mechanism */
    @media (hover: none) { ... }

    /* One or more available input mechanism(s) 
       can hover over elements with ease */
    @media (any-hover: hover) { ... }


    /* One or more available input mechanism(s) cannot 
       hover (or there are no pointing input mechanisms) */
    @media (any-hover: none) { ... }

媒体查询也可以在JS中使用:

if(window.matchMedia("(any-hover: none)").matches) {
    // do sth
}

有关:

W3文档:https//www.w3.org/TR/mediaqueries-4/#mf-interaction

浏览器支持:https : //caniuse.com/#search=media%20features

相似的问题:检测客户端设备是否支持:hover和:focus状态


我个人很喜欢这个答案,但根据caniuse.com,截至目前(10/19),@ media悬停和指针CSS查询仅在全球约85%的设备上可用。当然还不错,最好是95%以上。希望这将很快成为设备上的标准配置。
MQuiggGeorgia,

1
@MQuiggGeorgia基本上,我基本上同意您的批评,但尚无处支持。我仍然认为caniuse.com支持91.2%(caniuse.com/#feat=css-media-interaction)。仔细看一下,除IE 11和移动平台上的特殊扁平化浏览器外,其他任何地方都支持它。公平地说,这对于任何现代功能都是正确的,因为微软很早以前就停止实现IE功能。对于IE 11,您可以在此处使用其他答案的备用。
Blackbam

23

@Wyatt的回答很好,给了我们很多思考。

就我而言,我选择侦听第一个交互,然后才设置行为。因此,即使用户有鼠标,如果第一次交互是触摸,我也将其视为触摸设备。

考虑事件处理给定顺序

  1. 触摸开始
  2. 触摸移动
  3. 触摸端
  4. 鼠标移到
  5. 鼠标移动
  6. 按下鼠标
  7. 鼠标向上
  8. 点击

我们可以假设,如果在触摸之前触发了鼠标事件,则它是真正的鼠标事件,而不是模拟事件。示例(使用jQuery):

$(document).ready(function() {
    var $body = $('body');
    var detectMouse = function(e){
        if (e.type === 'mousedown') {
            alert('Mouse interaction!');
        }
        else if (e.type === 'touchstart') {
            alert('Touch interaction!');
        }
        // remove event bindings, so it only runs once
        $body.off('mousedown touchstart', detectMouse);
    }
    // attach both events to body
    $body.on('mousedown touchstart', detectMouse);
});

那对我有用


对我不起作用,Ipad Safari(IOS8.3)也会检测到带有此代码段的鼠标
netzaffin 2015年

3
@netzaffin。感谢您的反馈,我发现使用mousedown而不是mouseover可以使其更加一致。您能否看一下您的IOS上的这个小提琴,让我知道结果?干杯jsfiddle.net/bkwb0qen/15/embedded/result
雨果席尔瓦

1
如果您的触摸屏带有鼠标,则只会检测到最先使用的输入法。
0xcaff

11

只能检测浏览器是否具有触摸功能。无法知道它是否实际连接了触摸屏或鼠标。

如果检测到触摸功能,则可以通过监听触摸事件而不是鼠标事件来确定使用的优先级。

要检测跨浏览器的触摸功能:

function hasTouch() {
    return (('ontouchstart' in window) ||       // html5 browsers
            (navigator.maxTouchPoints > 0) ||   // future IE
            (navigator.msMaxTouchPoints > 0));  // current IE10
}

然后可以使用它来检查:

if (!hasTouch()) alert('Sorry, need touch!);

或选择要收听的事件,或者:

var eventName = hasTouch() ? 'touchend' : 'click';
someElement.addEventListener(eventName , handlerFunction, false);

或针对触摸与非触摸使用单独的方法:

if (hasTouch() === true) {
    someElement.addEventListener('touchend' , touchHandler, false);

} else {
    someElement.addEventListener('click' , mouseHandler, false);

}
function touchHandler(e) {
    /// stop event somehow
    e.stopPropagation();
    e.preventDefault();
    window.event.cancelBubble = true;
    // ...
    return false; // :-)
}
function mouseHandler(e) {
    // sorry, touch only - or - do something useful and non-restrictive for user
}

对于鼠标,只能检测是否正在使用鼠标,而不是是否存在。可以设置一个全局标志来指示通过使用检测到了鼠标(类似于现有答案,但有所简化):

var hasMouse = false;

window.onmousemove = function() {
    hasMouse = true;
}

(一个不能包含,mouseup或者mousedown也可以通过触摸触发这些事件)

浏览器限制了对低级系统API的访问,这是能够检测到所用系统的功能(如系统的硬件功能)所必需的。

可能有可能编写一个插件/扩展来访问这些插件/扩展,但是为此,通过JavaScript和DOM限制了这种检测,因此必须编写特定于各种OS平台的插件。

因此,可以得出结论:只能通过“良好的猜测”来估计这种检测。


8

什么时候 浏览器中提供Media Queries Level 4时,我们将能够使用“指针”和“悬停”查询来用鼠标检测设备。

如果我们真的想将该信息传达给Javascript,可以使用CSS查询根据设备类型设置特定样式,然后使用 getComputedStyle在Javascript中该样式来读取该样式,并从中获取原始设备类型。

但是可以随时连接拔下鼠标,并且用户可能希望在触摸和鼠标之间切换。因此,我们可能需要检测到此更改,并提供更改界面或自动执行此操作。


1
具体来说,any-pointerany-hover将使您研究所有适用的设备功能。很高兴看到我们将来如何解决这个问题!:)
乔丹·格雷

2
window.matchMedia(“(任何指针:粗糙的)”)。matches === true吗?
2015年

7

由于您打算提供一种无论如何在界面之间切换的方法,仅要求用户单击链接或按钮以“输入”应用程序的正确版本是否可行?然后,您可以记住他们对以后访问的偏爱。它不是高科技,但100%可靠:-)


2
实际上,这是一个很好的建议,但是它会延迟用户进入真实界面的时间。另外,我必须提供一种在初始选择后进行切换的方法。最终被比如果可以简单地检测到更多的工作..
乔恩Gjengset

1
询问用户显然是最好的方法-如果不是始终做到万无一失-并为您提供方便的地方来提交升级通知,而不是什么。我认为你是在思考“问题” ..
T4NK3R

4

@SamuelRossille我所知道的浏览器都没有暴露出鼠标的存在(或缺少鼠标)。

因此,话虽这么说,我们只需要尝试并利用现有的...事件就可以做到最好。我知道这不是您要找的东西...同意,这远非理想。

我们会尽力找出用户在任何给定时刻是使用鼠标还是触摸。这是一个使用jQuery&Knockout的简单又肮脏的示例:

//namespace
window.ns = {};

// for starters, we'll briefly assume if touch exists, they are using it - default behavior
ns.usingTouch = ko.observable(Modernizr.touch); //using Modernizr here for brevity.  Substitute any touch detection method you desire

// now, let's sort out the mouse
ns.usingMouse = ko.computed(function () {
    //touch
    if (ns.usingTouch()) {
        //first, kill the base mousemove event
        //I really wish browsers would stop trying to handle this within touch events in the first place
        window.document.body.addEventListener('mousemove', function (e) {
            e.preventDefault();
            e.stopImmediatePropagation();
        }, true);

        //remove mouse class from body
        $('body').removeClass("mouse");

        //switch off touch listener
        $(document).off(".ns-touch");

        // switch on a mouse listener
        $(document).on('mousemove.ns-mouse', function (e) {
            if (Math.abs(window.lastX - e.clientX) > 0 || window.lastY !== e.clientY) {
                ns.usingTouch(false);  //this will trigger re-evaluation of ns.usingMouse() and result in ns.usingMouse() === true
            }
        });

        return false;
    }
    //mouse
    else {
        //add mouse class to body for styling
        $('body').addClass("mouse");

        //switch off mouse listener
        $(document).off(".ns-mouse");

        //switch on a touch listener
        $(document).on('touchstart.ns-touch', function () { ns.usingTouch(true) });

        return true;
    }
});

//tests:
//ns.usingMouse()
//$('body').hasClass('mouse');

您现在可以绑定/订阅usingMouse()usingTouch()和/或使用body设置界面样式。类来设置。一旦检测到鼠标光标并在touchstart上,界面就会来回切换。

希望我们很快会从浏览器供应商那里得到一些更好的选择。


2

通过将浏览器签名与其数据库进行比较,Tera-WURFL可以告诉您正在访问您站点的设备的功能。看看它,它是免费的!


1
这对于可能带有或不带有触摸屏和鼠标的设备不起作用。例如,桌面Windows电脑可以连接到触摸屏,但通常也有一个鼠标,而平板电脑也可以运行Windows,但可能没有鼠标连接..
乔恩Gjengset

@Jonhoo仅假定桌面操作系统已连接鼠标。毕竟,他们必须支持各种不是为触摸屏开发的软件。
Gigi 2012年

1
运行普通Windows 8的平板电脑怎么样?还是Linux?还是运行Android的笔记本电脑?
Jon Gjengset

2
@Jonhoo显然,这种方法不是最佳方法,但是还没有可移植的方式知道这一点。如果正在使用Android笔记本电脑运行,则只需假设它具有触摸功能即可。如果正在运行Windows8平板电脑,则只需假定它具有鼠标功能即可(操作系统必须为非触摸程序模拟鼠标)。
Gigi 2012年

现在这已经过时,不再适用。
工程师

2

您为什么不仅仅检测它是否具有感应触摸和/或对鼠标移动做出反应的能力?

// This will also return false on
// touch-enabled browsers like Chrome
function has_touch() {
  return !!('ontouchstart' in window);
}

function has_mouse() {
  return !!('onmousemove' in window);
}

4
因为某些浏览器(例如IE9)报告该功能存在,即使它永远不会被触发。我相信这也是“正确”的行为。
Jon Gjengset

为什么要使用函数?就has_touch = 'ontouchstart' in window足够了,依此类推。
vsync

好吧,至少在OS X的Chrome 47上可以使用。报告没有ontouchstart。
phreakhead '16

2

在类似情况下,这也对我有用。基本上,假设用户没有鼠标,直到您看到一系列连续的鼠标移动而又不干预mousedown或mouseup为止。不是很优雅,但可以。

var mousedown = false;
var mousemovecount = 0;
function onMouseDown(e){
    mousemovecount = 0;
    mousedown = true;
}
function onMouseUp(e){
    mousedown = false;
    mousemovecount = 0;
}
function onMouseMove(e) {
    if(!mousedown) {
        mousemovecount++;
        if(mousemovecount > 5){
            window.removeEventListener('mousemove', onMouseMove, false);
            console.log("mouse moved");
            $('body').addClass('has-mouse');
        }
    } else {
        mousemovecount = 0;
    }
}
window.addEventListener('mousemove', onMouseMove, false);
window.addEventListener('mousedown', onMouseDown, false);
window.addEventListener('mouseup', onMouseUp, false);


0

正如其他人指出的那样,确定地检测他们是否有鼠标是不可靠的。根据设备的不同,可以轻松更改。绝对是可靠的,至少在文档规模上,布尔值true或false绝对是无法做到的。

触摸事件和鼠标事件是排他的。因此,这有助于采取不同的措施。问题在于触摸事件更接近于鼠标的上/下/移动事件,并且还会触发单击事件。

根据您的问题,您说要悬停预览。除此之外,我不知道您界面的其他任何细节。我假设在缺少鼠标的情况下您希望水龙头进行预览,而单击则由于悬停预览而执行不同的操作。

如果是这种情况,您可以采取某种惰性的检测方法:

在onclick事件之前,始终会使用鼠标在onmouseover事件之前。因此,请注意,鼠标位于已单击元素的顶部。

您可以通过文档范围内的onmousemove事件来执行此操作。您可以event.target用来记录鼠标所在的元素。然后,在您的onclick事件中,您可以检查鼠标是否实际上在被单击的元素(或元素的子元素)上。

从那里,您可以选择两者都依赖于click事件,并根据结果执行A或B操作。如果某些触摸设备不发出click事件(相反,您将不得不依赖ontouch *事件),则B操作可能无效。


0

我认为无法识别仅触摸设备(据我所知)。主要问题是触摸设备也会触发所有鼠标和键盘事件。请参见以下示例,这两个警报对于触摸设备均返回true。

function is_touch_present() {
  return ('ontouchstart' in window) || ('onmsgesturechange' in window);
}

function is_mouse_present() {
  return (('onmousedown' in window) && ('onmouseup' in window) && ('onmousemove' in window) && ('onclick' in window) && ('ondblclick' in window) && ('onmousemove' in window) && ('onmouseover' in window) && ('onmouseout' in window) && ('oncontextmenu' in window));
}

alert("Touch Present: " + is_touch_present());
alert("Mouse Present: " + is_mouse_present());

2
Safari浏览器iPad的回报true'onmousedown' in window
VSYNC

0

我认为最好的主意是mousemove听众(目前是最佳答案)。我认为需要对该方法进行一些调整。正如您在本iOS讨论中所看到的,基于触摸的浏览器的确可以模拟mousemove事件。,因此我们应该谨慎一些。

有道理的是,基于触摸的浏览器将仅在用户点击屏幕(用户的手指向下)时模拟此事件。这意味着我们应该在mousemove处理程序中添加一个测试,以查看事件期间哪个鼠标按钮按下(如果有)。如果没有鼠标按钮按下,我们可以安全地假定存在真实的鼠标。如果按下鼠标按钮,则测试仍不确定。

那么如何实现呢?这个问题表明,检查在mousemove期间哪个鼠标按钮被按下的最可靠方法是实际监听文档级别的3个事件:mousemove,mousedown和mouseup。上下只会设置一个全局布尔标志。此举将执行测试。如果您有一个动作,并且布尔值是false,则可以假定存在鼠标。请参阅问题以获取确切的代码示例。

最后一条评论。该测试不是理想的,因为它不能在加载时间内执行。因此,我将使用以前建议的渐进增强方法。默认情况下,显示不支持鼠标特定的悬停界面的版本。如果发现了鼠标,请在运行时使用JS启用此模式。对用户来说,这应该是无缝的。

为了支持用户配置的更改(即鼠标已断开连接),您可以定期重新测试。尽管我认为在这种情况下最好将两种模式简单地通知用户,然后让用户手动在两种模式之间进行切换(就像移动/台式机选项始终可以相反)。


感谢您提供良好的解决方法建议...我认为主要问题没有得到解决,我将不得不诉诸其中之一
Samuel Rossille

不幸的是,单击ipad会触发mousemove。仅在模拟器上测试过。对于hasMouse()我正在使用if(!('ontouchstart'in window))return true; 但不适用于支持触摸功能的笔记本电脑。
克里斯·古纳瓦德纳

@Chris G-iPad地狱...(把我的头撞在墙上)
vsync

0

在各种PC,Linux,iPhone,Android手机和标签上进行一些测试。很奇怪,没有简单的防弹解决方案。当某些具有触摸功能但没有鼠标的应用程序仍然出现触摸和鼠标事件时,就会出现问题。由于确实要支持纯鼠标和纯触摸实例,因此要同时处理这两个实例,但这会导致用户交互的两次发生。如果可以知道设备上不存在鼠标,那么可以知道忽略假的/插入的鼠标事件。如果遇到MouseMove,则尝试设置标志,但是某些浏览器会抛出伪造的MouseMove以及MouseUp和MouseDown。尝试检查时间戳,但认为这太冒险了。底线:我发现创建假鼠标事件的浏览器总是在插入的MouseDown之前插入单个MouseMove。在我的99.99%的案例中,在具有真实鼠标的系统上运行时,有多个连续的MouseMove事件-至少两个。因此,请跟踪系统是否遇到两个连续的MouseMove事件,并声明如果永不满足此条件,则不存在任何鼠标。这可能太简单了,但是它适用于我所有的测试设置。认为我会坚持下去,直到找到更好的解决方案。-吉姆W


0

jQuery中用于检测鼠标使用情况的简单解决方案,解决了移动设备还触发“ mousemove”事件的问题。只需添加一个touchstart侦听器即可删除mousemove侦听器,这样它就不会在触摸时触发。

$('body').one('touchstart.test', function(e) {
  // Remove the mousemove listener for touch devices
  $('body').off('mousemove.test');
}).one('mousemove.test', function(e) {
  // MOUSE!
});

当然,该设备仍可以是触摸AND鼠标,但是以上内容可以保证使用了真正的鼠标。


0

刚刚找到了一个我认为非常优雅的解决方案。

// flag as mouse interaction by default
var isMouse = true;

// detect a touch event start and flag it
$(window).on('touchstart', function () {
  // if triggers touchstart, toggle flag
  // since touch events come before mouse event / click
  // callback of mouse event will get in callback
  // `isMouse === false`
  isMouse = false;
});

// now the code that you want to write
// should also work with `mouse*` events
$('a.someClass').on('click', function () {
  if (isMouse) {
    // interaction with mouse event
    // ...
  } else {
    // reset for the next event detection
    // this is crucial for devices that have both
    // touch screen and mouse
    isMouse = true;

    // interaction with touch event
    // ...
  }
});

0

我遇到了同样的问题,一次点击也被注册为一次点击。在阅读完投票最多的答案的评论后,我想出了自己的解决方案:

var body = document.getElementsByTagName('body')[0];
var mouseCount = 0;

// start in an undefined state 
// (i use this to blend in elements once we decide what input is used)
var interactionMode = 'undefined';


var registerMouse = function() {
  // count up mouseCount every time, the mousemove event is triggered
  mouseCount++;

  // but dont set it instantly. 
  // instead wait 20 miliseconds (seems to be a good value for multiple move actions), 
  // if another mousemove event accoures switch to mouse as interaction 
  setTimeout(function() {
    // a touch event triggers also exactly 1 mouse move event.
    // So only if mouseCount is higher than 1 we are really moving the cursor by mouse.
    if (mouseCount > 1) {
      body.removeEventListener('mousemove', registerMouse);
      body.removeEventListener('touchend', registerTouch);

      interactionMode = 'mouse';
      console.log('now mousing');
      listenTouch();
    }

    // set the counter to zero again
    mouseCount = 0;
  }, 20);
};

var registerTouch = function() {
  body.removeEventListener('mousemove', registerMouse);
  body.removeEventListener('touchend', registerTouch);

  interactionMode = 'touch';
  console.log('now touching');
  mouseCount = 0;

  listenMouse();
};

var listenMouse = function() {
  body.addEventListener("mousemove", registerMouse);
};
var listenTouch = function() {
  body.addEventListener("touchend", registerTouch);
};

listenMouse();
listenTouch();

// after one second without input, assume, that we are touching
// could be adjusted to several seconds or deleted
// without this, the interactionMode would stay 'undefined' until first mouse or touch event
setTimeout(function() {
  if (!body.classList.contains('mousing') || body.classList.contains('touching')) {
    registerTouch();
  }
}, 1000);
/* fix, so that scrolling is possible */

html,
body {
  height: 110%;
}
Mouse or touch me

我发现的唯一问题是,您必须能够滚动才能正确检测到触摸事件。单个选项卡(触摸)可能会出现问题。


0

我花了几个小时为我的Phonegap应用找出了这个问题,然后想到了这个问题。如果触发的事件是“被动”事件,它将生成一个控制台警告,这意味着它不会促动任何更改,但是可以工作!我将对任何改进或更好的方法感兴趣。但这有效地使我可以普遍使用$ .touch()。

$(document).ready(function(){
  $("#aButton").touch(function(origElement, origEvent){
    console.log('Original target ID: ' + $(origEvent.target).attr('id'));
  });
});

$.fn.touch = function (callback) {
    var touch = false;
    $(this).on("click", function(e){
        if (!touch)
        {
            console.log("I click!");
            let callbackReal = callback.bind(this);
            callbackReal(this, e);
        }else{
            touch = true;
        }
        touch = false;
    });
    $(this).on("touchstart", function(e){
        if (typeof e.touches != typeof undefined)
        {
            e.preventDefault();
            touch = true;
            console.log("I touch!");
            let callbackReal = callback.bind(this);
            callbackReal(this, e);
        }
    });
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<button id="aButton">A Button</button>


0

我在这里看到的主要问题是,大多数触摸设备都会触发一个鼠标事件以及相应的核心触摸事件(touchstart-> mousedown,touchmove-> mousemove等)。对于仅键盘的键盘,最后是现代键盘的键盘,它们具有通用的浏览器,因此您甚至无法检测到MouseEvent类的存在。

在我看来,这里较为轻松的解决方案是在启动时显示菜单(仅对键盘用户提供“ alt”管理),并可能将选择存储在localStorage / cookies / serverside中,否则在下一个选择中保留相同的选择访客来的时间。


-4

我强烈建议您反对这种方法。考虑使用台式机大小的触摸屏设备,您需要解决一系列不同的问题。

请在没有鼠标的情况下使您的应用程序可用(即没有悬停预览)。


1
这正是我想要做的。我正在尝试创建一个在平板电脑(没有鼠标)和鼠标上都能以最佳方式工作的界面,但是这些界面必然有很大的不同。
Jon Gjengset

我大致同意。最好使用设备检测(例如DeviceAtlas)并在加载时选择提供的接口。
Teemu Ikonen'2

-4

想推荐一个对我有帮助的脚本:

我已阅读并尝试了所有建议的内容,但均未获得足够的结果。

然后我研究了更多内容,并找到了这段代码-device.js

我在我的客户的网站使用这个,来检测鼠标的存在:
<html>应该有desktop一流的),似乎很不错,和touch支持,我只是做定期检查'ontouchend' in document从两个检测和使用的信息承担具体的事情,我需要。


这相当于UA嗅探,在本主题中已经多次提出。它无法解决Windows 8等具有鼠标和触摸功能的设备的情况,并且绝对不能作为未来的证明。
雨果席尔瓦

我用它来解决您在客户端应用程序中提到的EXACT情况,并且效果很好。这是未来的证明,因为它是由开发人员维护的。
vsync

2
我提到的情况(带触摸功能的笔记本电脑)将被您的脚本标识为“台式机”,即使我可能不使用鼠标也是如此。“这是未来的证明,因为它是由开发人员维护的” –我认为您在这里完全错过了“未来证明”的要点。而且,如果您按照说明阅读并尝试了所有内容,您会注意到Gigi的答案已经暗示了UA嗅探。
雨果席尔瓦

-7

通常,最好是检测是否支持鼠标悬停功能,而不是检测OS /浏览器类型。您可以通过以下操作简单地做到这一点:

if (element.mouseover) {
    //Supports the mouseover event
}

确保您执行以下操作:

if (element.mouseover()) {
    // Supports the mouseover event
}

后者实际上将调用该方法,而不是检查其是否存在。

您可以在这里阅读更多信息:http : //www.quirksmode.org/js/support.html


2
我真的不知道从您的帖子中可以得到什么,但是如果($('body')[0]中的'onmouseover')alert('onmouseover'); 在iPhone中也显示一条消息
nraynaud 2011年

1
这仅检查是否定义了鼠标悬停功能,几乎所有浏览器都将定义该功能。它不会检测是否确实存在鼠标。
乔恩·詹杰塞特
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.