Обнаружение, что браузер не имеет мыши и только для сенсорного - PullRequest
137 голосов
/ 20 октября 2011

Я разрабатываю веб-приложение (не веб-сайт со страницами интересного текста) с совершенно другим интерфейсом для касания (ваш палец скрывает экран при нажатии) и мыши (в значительной степени зависит от предварительного просмотра при наведении курсора). Как я могу определить, что у моего пользователя нет мыши, чтобы предоставить ему правильный интерфейс? Я планирую оставить переключатель для людей с мышью и сенсорным (как некоторые ноутбуки).

Возможность сенсорного события в браузере на самом деле не означает, что пользователь использует сенсорное устройство (например, 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);

Ответы [ 24 ]

0 голосов
/ 05 июля 2018

Я столкнулся с той же проблемой, где одно касание также было зарегистрировано как щелчок. После того, как я прочитал комментарии самых популярных ответов, я нашел собственное решение:

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 голосов
/ 03 августа 2013

Лучшей идеей, на мой взгляд, является слушатель mousemove (в настоящее время лучший ответ).Я считаю, что этот метод нужно немного доработать.Это правда, что сенсорные браузеры эмулируют даже событие mousemove, как вы можете видеть в этом обсуждении iOS , поэтому мы должны быть немного осторожнее.

Имеет смысл, что сенсорныйбраузеры будут эмулировать это событие только тогда, когда пользователь касается экрана (палец пользователя опущен).Это означает, что мы должны добавить тест во время нашего обработчика перемещения мыши, чтобы увидеть, какая кнопка мыши нажата (если есть) во время события.Если ни одна кнопка мыши не нажата, мы можем с уверенностью предположить, что настоящая мышь присутствует.Если кнопка мыши нажата, тест остается безрезультатным.

Так как бы это реализовать?Этот вопрос показывает, что наиболее надежный способ выяснить, какая кнопка мыши нажата во время перемещения мыши, - это фактически прослушивать 3 события на уровне документа: mousemove, mousedown и mouseup.Вверх и вниз будет установлен только глобальный логический флаг.Ход выполнит тест.Если у вас есть ход и логическое значение ложно, мы можем предположить, что мышь присутствует.См. Вопрос для точных примеров кода.

Один последний комментарий. Этот тест не идеален, потому что он не может быть выполнен во время загрузки.Поэтому я бы использовал прогрессивный метод улучшения, как было предложено ранее.По умолчанию показывают версию, которая не поддерживает специфический для мыши интерфейс наведения мыши.Если мышь обнаружена, включите этот режим во время выполнения, используя JS.Это должно выглядеть как можно более незаметно для пользователя.

Чтобы поддержать изменения в конфигурации пользователя (т. Е. Мышь была отключена), вы можете периодически повторять тестирование.Хотя я полагаю, что в этом случае будет лучше просто уведомить пользователя о двух режимах и позволить пользователям вручную переключаться между ними (как, например, выбор мобильного / настольного компьютера, который всегда можно изменить).

0 голосов
/ 27 февраля 2019

Я часами разбирался с этой проблемой для своего приложения 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 голосов
/ 20 октября 2011

Как правило, лучше определить, поддерживается ли функция наведения мыши, а не определять тип ОС / браузера.Вы можете сделать это просто следующим образом:

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

Убедитесь, что вы не делаете следующее:

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

Последний действительно вызоветметод, а не проверять его существование.

Вы можете прочитать больше здесь: http://www.quirksmode.org/js/support.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...