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

2020/11/11 01:23 · javascript ·  · 0评论

我正在开发一个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);

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

  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。

这应该导致您以下:

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

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

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

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

(在哪里listenunlisten委托给addEventListenerattachEvent视情况而定。)

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

截至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状态

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

那对我有用

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

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

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

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平台的插件。

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

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

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

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

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

@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上,界面就会来回切换。

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

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

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

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

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

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

看看modenizr的功能之一就是触摸

http://modernizr.com/docs/#features-misc

虽然我还没有进行充分的测试,但是效果似乎很好

这也可以从modernizr页面
http://www.html5rocks.com/en/mobile/touchandmouse/

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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鼠标,但是以上内容可以保证使用了真正的鼠标。

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

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

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

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

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

我花了数小时为我的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>

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

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

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

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

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

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

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

我在我的客户的网站使用这个,来检测鼠标的存在:

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

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

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

请确保您执行以下操作:

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

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

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

本文地址:http://javascript.askforanswer.com/jianceliulanqimeiyoushubiaobingqiejinshichumoshi.html
文章标签: ,   ,   ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!