ChatGPT解决这个技术问题 Extra ChatGPT

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

我正在开发一个 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 上的一篇相当有用的帖子,用于检测鼠标的各种状态(点击、位置、等),但鼠标是否实际存在的结果为零。
也许那是因为谷歌没有帮助我在这里问它。
您是否尝试过来自 jquery 的 document mouseenter? $(document).mouseenter(function(e) { alert("mouse"); });
在考虑了近十种有希望的途径后,几分钟内就拒绝了每一种,这个问题让我非常疯狂。

d
danronmoon

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

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 something
}

有关的:

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

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

类似问题:Detect if a client device supports :hover and :focus states


我个人喜欢这个答案,但截至目前 (10/19),根据 caniuse.com 的数据,@media hover 和 pointer CSS 查询仅在全球约 85% 的设备上可用。当然还不错,最好是95%以上。希望这将很快成为设备的标准。
@MQuiggGeorgia 基本上我基本上同意你的批评,它还没有在所有地方得到支持。我仍然 caniuse.com 说它支持 91.2% (caniuse.com/#feat=css-media-interaction)。仔细观察,除了 IE 11 和移动设备上的特殊扁平化浏览器外,它在所有地方都受支持。公平地说,任何现代功能都是如此,因为微软很久以前就停止了 IE 功能。对于 IE 11,您可以在此处使用其他答案的后备。
2020 年 9 月:我正在 Android 智能手机中尝试媒体匹配(悬停:悬停),它匹配,而在 w3 链接中说它不应该
@raquelhortab 如果 W3 说它不应该比它不应该。您使用哪种浏览器?
出于某种原因,window.matchMedia("(any-pointer: fine)").matches 在我的所有移动浏览器和桌面上都返回 true。 window.matchMedia("(any-hover: hover)").matches 也总是返回 true,即使在没有鼠标的移动设备上也是如此。只有 window.matchMedia("(any-pointer: coarse)").matches 在移动设备上返回 true,在桌面设备上返回 false,但它不考虑连接的鼠标或 s-pen。
d
danronmoon

主要问题是您有以下不同类别的设备/用例:

鼠标和键盘(台式机) 仅限触控(手机/平板电脑) 鼠标、键盘和触控(触控笔记本电脑) 触控和键盘(平板电脑上的蓝牙键盘) 仅限鼠标(禁用用户/浏览首选项) 仅键盘(禁用用户/浏览首选项)触摸和鼠标(即来自 Galaxy Note 2 笔的悬停事件)

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

您假设浏览器中存在事件构造函数不是前进的好方法是正确的(并且它有些不一致)。此外,除非您正在跟踪一个非常具体的事件或只是试图排除上述几个类别,否则使用事件本身并不是完全的证明。

例如,假设您发现用户发出了真正的 mousemove(不是来自触摸事件的错误,请参阅 http://www.html5rocks.com/en/mobile/touchandmouse/)。

然后呢?

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

无论哪种方式,您都在增加玻璃的时间,因为您必须等待事件触发。

但是,当您的高贵用户决定拔下鼠标并完全触摸时会发生什么......您是否等待他触摸您现在拥挤的界面,然后在他努力确定您现在拥挤的 UI 之后立即更改它?

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

我们想检测鼠标的存在我们可能无法在事件触发之前检测到它因此,我们正在检测的是是否在此会话中使用了鼠标——它不会立即从页面加载我们可能也无法检测到没有鼠标——它在为真之前是未定义的(我认为这比在被证明之前将其设置为假更有意义)而且我们可能无法检测到鼠标是否在会话中断开连接——这与用户只是放弃鼠标没有什么区别

顺便说一句:浏览器确实知道用户何时插入鼠标/连接到键盘,但不会将其暴露给 JavaScript .. dang!

这应该会引导您完成以下操作:

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

不过,渐进增强的想法在这里非常适用。无论用户所处的环境如何,都可以打造顺畅运行的体验。然后根据浏览器功能/媒体查询做出假设,以添加在假设上下文中相关的功能。鼠标的存在只是不同设备上的不同用户体验您的网站的众多方式之一。在其内核中创建具有优点的东西,不要太担心人们如何点击按钮。


很好的答案。希望用户始终拥有屏幕!我认为构建一个适合当前用户交互模式的界面是有意义的。在触控笔记本电脑上,当用户从鼠标切换到触控时,调整应用程序(即 :hover 元素等)是有意义的。用户当前似乎不太可能同时使用鼠标+触摸(我的意思是comoonn就像将2个鼠标连接到同一台计算机哈哈哈)
@SebastienLorber - 不想告诉你,但用户不一定总是有一个屏幕。 (Is it possible to use javascript to detect if a screen reader is running on a users machine?)
D
Dan

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

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

(其中 listenunlisten 酌情委托给 addEventListenerattachEvent。)

希望这不会导致太多的视觉卡顿,如果您需要基于模式的大量重新布局,那会很糟糕......


这是一个好主意,但不幸的是,当应用程序的 UI 取决于鼠标是否可用时,响应延迟将使其无法使用。如果应用程序可能是 iframed,则尤其如此,因此鼠标事件只会在鼠标在 iframe 本身上移动..
如果应用程序以启动画面和“继续”按钮启动,这可能会起作用。如果鼠标在第一个 mousedown 事件之前移动,那么你有一个鼠标。只有当按钮直接加载在鼠标下方并且用户的手非常稳定时(即使移动 1 个像素也应该被拾取),它才会失败。
好主意,但在我们的测试中似乎不起作用。 iPad 触发此事件。
@JeffAtwood 您最终在您的案子中做了什么?
iPad 肯定会在 mousedown 事件之前触发 mousemove 事件。我发现 mousedown count > 0 和 mousedown count == mousemove count 是检测没有鼠标的好方法。我无法用真正的鼠标复制它。
H
Hugo Silva

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

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

考虑 given order in which events are processed

touchstart touchmove touchend mouseover mousemove mousedown mouseup click

我们可以假设如果鼠标事件在触摸之前被触发,它是一个真实的鼠标事件,而不是模拟的。示例(使用 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。感谢您的反馈,我发现使用 mousedown 而不是 mouseover 更加一致。你能从你的 IOS 看一下这个小提琴并让我知道结果吗?干杯jsfiddle.net/bkwb0qen/15/embedded/result
如果您有带鼠标的触摸屏,则只会检测最先使用的输入法。
d
danronmoon

只能检测浏览器是否支持触摸。没有办法知道它是否真的连接了触摸屏或鼠标。

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

跨浏览器检测触摸功能:

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

(不能包含 mouseupmousedown,因为这些事件也可以通过触摸触发)

浏览器限制了对低级系统 API 的访问,这些 API 是检测正在使用的系统的硬件功能等特性所必需的。

有可能编写一个插件/扩展来访问这些,但通过 JavaScript 和 DOM,这种检测仅限于此目的,并且必须编写一个特定于各种操作系统平台的插件。

所以总而言之:这种检测只能通过“好的猜测”来估计。


j
joeytwiddle

Media Queries Level 4 在浏览器中可用时,我们将能够使用“指针”和“悬停”查询来检测带有鼠标的设备。

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

但是鼠标可以随时连接或拔出,用户可能想要在触摸和鼠标之间切换。所以我们可能需要检测这种变化,并提供改变界面或自动这样做。


具体来说,any-pointer and any-hover 将让您调查所有适用的设备功能。很高兴看到我们将来如何解决这个问题! :)
window.matchMedia("(任何指针:粗略)").matches === true ?
B
Brandan

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


这实际上是一个非常好的建议,但它会延迟用户进入真实界面之前的时间。此外,我必须提供一种在初始选择后进行切换的方式。最终比可以简单地检测到更多的工作..
询问用户显然是最好的方式——如果不是万无一失的话——并且给你一个方便的地方来发布升级通知等等。我认为您过度思考“问题”..
1
12 revs

@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.mouse 类设置界面样式。一旦检测到鼠标光标并在 touchstart 上,界面就会来回切换。

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


M
Michael Condouris

在类似的情况下,这对我有用。基本上,假设用户没有鼠标,直到您看到一系列连续的鼠标移动,而没有干预 mousedowns 或 mouseups。不是很优雅,但它有效。

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

i
iblue

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

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

因为某些浏览器(例如 IE9)报告该功能存在,即使它永远不会被触发。我相信这也是“正确”的行为。
好吧,它至少适用于 OS X 的 Chrome 47。报告没有 ontouchstart。
G
Gigi

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


这不适用于可能具有或不具有触摸屏和鼠标的设备。例如,台式 Windows 计算机可能连接到触摸屏,但通常也有鼠标,而平板电脑也可能运行 Windows,但可能没有连接鼠标。
@Jonhoo 假设桌面操作系统连接了鼠标。毕竟,他们必须支持范围广泛的软件,而这些软件开发时并未考虑到触摸屏。
运行普通 Windows 8 的平板电脑怎么样?还是Linux?还是运行 Android 的笔记本电脑?
@Jonhoo 显然,这种方法不是最优的,但是(还)没有可移植的方法来知道这一点。如果您正在运行一台装有 Android 系统的笔记本电脑,则假设它具有触控功能。如果您正在运行 Windows8 平板电脑,只需假设它具有鼠标功能(操作系统必须为非触摸程序模拟鼠标)。
这现在已经过时了,以至于不再相关。
J
Jannis Nexor Ianus Betz

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

var body = document.getElementsByTagName('body')[0];变量鼠标计数 = 0; // 以未定义状态开始 // (一旦我们决定使用什么输入,我就使用它来混合元素) var interactionMode = 'undefined'; var registerMouse = function() { // 每次向上计数 mouseCount,触发 mousemove 事件 mouseCount++; // 但不要立即设置它。 // 而是等待 20 毫秒(对于多个移动操作来说似乎是一个不错的值),// 如果另一个 mousemove 事件作为交互切换到鼠标 setTimeout(function() { // 一个触摸事件也恰好触发 1 个鼠标移动事件。 // 所以只有当 mouseCount 大于 1 时我们才真正通过鼠标移动光标 if (mouseCount > 1) { body.removeEventListener('mousemove', registerMouse); body.removeEventListener('touchend', registerTouch); interactionMode = 'mouse'; console.log('now mousing'); listenTouch(); } // 再次将计数器设置为零 mouseCount = 0; }, 20); }; var registerTouch = function() { body.removeEventListener('mousemove', registerMouse); body.removeEventListener('touchend', registerTouch);交互模式 = '触摸'; console.log('现在触摸');鼠标计数 = 0;听鼠(); }; var listenMouse = function() { body.addEventListener("mousemove", registerMouse); }; var listenTouch = function() { body.addEventListener("touchend", registerTouch); };听鼠();听触(); // 在没有输入的一秒后,假设我们正在触摸 // 可以调整到几秒或删除 // 如果没有这个,interactionMode 将保持“未定义”,直到第一次鼠标或触摸事件 setTimeout(function() { if ( !body.classList.contains('mousing') || body.classList.contains('touching')) { registerTouch(); } }, 1000); /* 修复,以便可以滚动 */ html, body { height: 110%; } 鼠标或触摸我

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


L
Luke

正如其他人指出的那样,明确检测他们是否有老鼠是不可靠的。这很容易改变,具体取决于设备。至少在文档规模上,这绝对是您无法使用布尔值 true 或 false 可靠地完成的事情。

触摸事件和鼠标事件是互斥的。所以这可以在一定程度上帮助采取不同的行动。问题是触摸事件更接近鼠标上/下/移动事件,并且还会触发单击事件。

从您的问题中,您说您希望悬停进行预览。除此之外,我不知道有关您的界面的任何其他细节。我假设在没有鼠标的情况下,您希望点击预览,而由于悬停预览,单击会执行不同的操作。

如果是这种情况,您可以采取一些懒惰的方法进行检测:

onclick 事件之前总是会出现一个带有鼠标的 onmouseover 事件。因此请注意,鼠标位于已单击的元素之上。

您可以使用文档范围的 onmousemove 事件来做到这一点。您可以使用 event.target 记录鼠标所在的元素。然后在您的 onclick 事件中,您可以检查鼠标是否实际上位于被单击的元素(或元素的子元素)上。

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


B
Bikas

我认为不可能识别仅触摸设备(当然据我所知)。主要问题是所有鼠标和键盘事件也是由触摸设备触发的。请参阅以下示例,对于触摸设备,两个警报都返回 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());

Safari ipad 为 'onmousedown' in window 返回 true
C
Community

我认为最好的主意是 mousemove 侦听器(目前是最佳答案)。我相信这种方法需要稍微调整一下。确实,基于触摸的浏览器甚至会模拟 mousemove 事件,正如您在 this iOS discussion 中看到的那样,所以我们应该小心一点。

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

那么这将如何实施呢?此 question 表明,在 mousemove 期间检查哪个鼠标按钮按下的最可靠方法是实际侦听文档级别的 3 个事件:mousemove、mousedown 和 mouseup。 up 和 down 只会设置一个全局布尔标志。移动将执行测试。如果你有一个动作并且布尔值是假的,我们可以假设鼠标存在。有关确切的代码示例,请参阅问题。

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

为了支持更改用户的配置(即鼠标已断开连接),可以定期重新测试。尽管我相信在这种情况下最好简单地通知用户这两种模式并让用户在它们之间手动切换(就像移动/桌面选择总是可以颠倒的)。


感谢您提供好的解决方法建议...我认为主要问题没有得到解决,我将不得不求助于其中之一
不幸的是,鼠标移动会在点击 ipad 时触发。仅用模拟器测试。对于 hasMouse() 我正在使用 if( !('ontouchstart' in window) ) return true;但不适用于支持触控的笔记本电脑。
j
jwasch

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


s
suncat100

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

当然,设备仍然可以是触摸和鼠标,但以上将保证使用的是真正的鼠标。


K
Koala Yeung

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

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

J
Jay

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

$(document).ready(function(){ $("#aButton").touch(function(origElement, origEvent){ console.log('原始目标ID:' + $(origEvent.target).attr('id ')); }); }); $.fn.touch = 函数(回调){ 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!"); 让callbackReal = callback.bind(this); callbackReal(this, e); } }); }


M
Michael

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

在我看来,这里不那么痛苦的解决方案是在启动时显示一个菜单(对仅键盘用户使用“alt”管理),并可能使用 localStorage/cookies/serverside 存储选择,或者在下一次保持相同的选择访客来的时间。


a
ashleedawg

运行代码片段(如下)来试试这个:

var msg = (window.matchMedia("(any-pointer: coarse)").matches ? "Touchscreen" : "Mouse");

var msg = (window.matchMedia("(any-pointer: rough)").matches ? "Touchscreen" : "Mouse"); document.getElementById('info').innerHTML = msg;身体{背景:黑色;颜色:矢车菊蓝; } #info { 位置:绝对;左:50%;最高:50%;变换:翻译(-50%,-50%);字体大小:30vmin;字体系列:verdana、arial、helvetica; }

(这里有关于 window.matchMedia 的更多信息。)


您可以同时拥有鼠标和触摸屏(某些 Windows 笔记本电脑具有多年的屏幕触摸功能......)
window.matchMedia("(any-pointer: coarse)").matches 在移动设备上返回 true,在桌面设备上返回 false,但它不考虑连接的鼠标或 s-pen。
C
Chris Broadfoot

我强烈建议不要使用这种方法。考虑一下触摸屏、桌面大小的设备,您需要解决一系列不同的问题。

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


这正是我想要做的。我正在尝试创建一个界面,该界面可以在平板电脑(无鼠标)和鼠标上以最佳方式工作,但这些界面必然非常不同。
我同意广泛。您最好使用设备检测(如 DeviceAtlas)并在加载时选择提供的界面。
A
Agamemnus

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

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

确保您不执行以下操作:

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

后者实际上会调用该方法,而不是检查它的存在。

您可以在此处阅读更多内容:http://www.quirksmode.org/js/support.html


我真的不知道从你的帖子中得到什么,但是 if ('onmouseover' in $('body')[0]) alert('onmouseover');在 iPhone 中也显示一条消息
这仅检查是否定义了鼠标悬停功能,几乎所有浏览器都将使用该功能。它不会检测鼠标是否真的存在。