javascript - тачскрин - modernizr 2.7 1 min js




Каков наилучший способ обнаружения устройства «сенсорного экрана» с использованием JavaScript? (20)

Я написал плагин jQuery, предназначенный для использования как на настольных, так и на мобильных устройствах. Я задавался вопросом, есть ли способ с JavaScript определить, имеет ли устройство сенсорный экран. Я использую jquery-mobile.js для обнаружения событий на сенсорном экране, и он работает на iOS, Android и т. Д., Но я также хотел бы написать условные утверждения на основе того, имеет ли устройство пользователя сенсорный экран.

Это возможно?


Эта проблема

Из-за гибридных устройств, которые используют комбинацию сенсорного и мышечного ввода, вам нужно динамически изменять состояние / переменную, которая контролирует, должен ли кусок кода работать, если пользователь является сенсорным пользователем или нет.

Прикоснитесь к устройствам, также mousemove по крану.

Решение

  1. Предположим, что при загрузке прикосновение ложно.
  2. Подождите, пока не будет touchstart событие touchstart , а затем установите значение true.
  3. Если был запущен touchstart, добавьте обработчик mousemove.
  4. Если время между двумя событиями mousemove событий составляет менее 20 мс, предположите, что они используют мышь в качестве входных данных. Удалите событие, поскольку оно больше не требуется, а mousemove - дорогое событие для устройств мыши.
  5. Как только touchstart будет запущен снова (пользователь вернулся к использованию touch), переменная вернется к истине. И повторите процесс, чтобы он определялся динамически. Если некоторым чудом mousemove будет уволен дважды при прикосновении абсурдно быстро (в моих тестах это практически невозможно сделать в течение 20 мс), следующий сенсорный старт вернет его к истине.

Протестировано в Safari iOS и Chrome для Android.

Примечание: не на 100% уверены в указателях-событиях для MS Surface и т. Д.

Демо-версия Codepen

const supportsTouch = 'ontouchstart' in window;
let isUsingTouch = false;

// `touchstart`, `pointerdown`
const touchHandler = () => {
  isUsingTouch = true;
  document.addEventListener('mousemove', mousemoveHandler);
};

// use a simple closure to store previous time as internal state
const mousemoveHandler = (() => {
  let time;

  return () => {
    const now = performance.now();

    if (now - time < 20) {
      isUsingTouch = false;
      document.removeEventListener('mousemove', mousemoveHandler);
    }

    time = now;
  }
})();

// add listeners
if (supportsTouch) {
  document.addEventListener('touchstart', touchHandler);
} else if (navigator.maxTouchPoints || navigator.msMaxTouchPoints) {
  document.addEventListener('pointerdown', touchHandler);
}

jQuery v1.11.3

В ответах есть много хорошей информации. Но в последнее время я потратил много времени, пытаясь связать все вместе в рабочее решение для достижения двух вещей:

  1. Определите, что используемое устройство является устройством типа сенсорного экрана.
  2. Определите, что устройство было прослушировано.

Помимо этого сообщения и обнаружения устройств сенсорного экрана с Javascript , я нашел этот пост Патриком Лауке чрезвычайно полезным: https://hacks.mozilla.org/2013/04/detecting-touch-its-the-why-not-the-how/

Вот код ...

$(document).ready(function() {
//The page is "ready" and the document can be manipulated.

    if (('ontouchstart' in window) || (navigator.maxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0))
    {
      //If the device is a touch capable device, then...
      $(document).on("touchstart", "a", function() {

        //Do something on tap.

      });
    }
    else
    {
      null;
    }
});

Важный! Метод *.on( events [, selector ] [, data ], handler ) должен иметь селектор, обычно элемент, который может обрабатывать событие «touchstart» или любое другое подобное событие, связанное с касаниями. В этом случае это элемент гиперссылки «a».

Теперь вам не нужно обращаться с обычным щелчком мыши в JavaScript, потому что вы можете использовать CSS для обработки этих событий с помощью селекторов для элемента гиперссылки «a»:

/* unvisited link */
a:link 
{

}

/* visited link */
a:visited 
{

}

/* mouse over link */
a:hover 
{

}

/* selected link */
a:active 
{

}

Примечание. Существуют и другие селектора ...


Все браузеры, за исключением Firefox для настольных ПК, всегда ИСТИННЫ, потому что Firefox для настольных ПК поддерживает гибкий дизайн для разработчика, даже вы нажимаете Touch-Button или нет!

Надеюсь, Mozilla установит это в следующей версии.

Я использую рабочий стол Firefox 28.

function isTouch()
{
    return !!("ontouchstart" in window) || !!(navigator.msMaxTouchPoints);
}

Вы можете использовать следующий код:

function isTouchDevice() {
   var el = document.createElement('div');
   el.setAttribute('ongesturestart', 'return;'); // or try "ontouchstart"
   return typeof el.ongesturestart === "function";
}

Источник: обнаружение сенсорного браузера и пост @mplungjan .

Вышеприведенное решение было основано на обнаружении поддержки событий без статьи для обхода браузера .

Вы можете проверить результаты на следующей тестовой странице .

Обратите внимание, что приведенный выше код проверяет только поддержку браузера касания, а не устройства.Поэтому, если у вас есть ноутбук с сенсорным экраном, у вашего браузера может не быть поддержки сенсорных событий. Недавняя Chrome поддерживает сенсорные события , но другой браузер не может.

Вы также можете попробовать:

if (document.documentElement.ontouchmove) {
  // ...
}

но он может не работать на устройствах iPhone.


Вы пытались использовать эту функцию? (Это то же самое, что и Modernizr.)

function is_touch_device() {  
  try {  
    document.createEvent("TouchEvent");  
    return true;  
  } catch (e) {  
    return false;  
  }  
}

ОБНОВЛЕНИЕ 1

document.createEvent("TouchEvent") начал возвращать true в последнем хроме (v. 17). Modernizr обновил это некоторое время назад. Проверьте тест Modernizr здесь .

Обновите свою функцию, чтобы она работала:

function is_touch_device() {
  return 'ontouchstart' in window;
}

ОБНОВЛЕНИЕ 2

Я обнаружил, что вышеописанное не работает на IE10 (возвращает false на MS Surface). Вот исправление:

function is_touch_device() {
  return 'ontouchstart' in window        // works on most browsers 
      || 'onmsgesturechange' in window;  // works on IE10 with some false positives
};

ОБНОВЛЕНИЕ 3

'onmsgesturechange' in window вернет true в некоторых версиях настольных компьютеров IE, поэтому это не является надежным. Это работает несколько более надежно:

function is_touch_device() {
  return 'ontouchstart' in window        // works on most browsers 
      || navigator.maxTouchPoints;       // works on IE10/11 and Surface
};

ОБНОВЛЕНИЕ 2018

Прошло время, и есть новые и лучшие способы проверить это. Я в основном извлек и упростил способ проверки Modernizr:

function is_touch_device() {
  var prefixes = ' -webkit- -moz- -o- -ms- '.split(' ');
  var mq = function(query) {
    return window.matchMedia(query).matches;
  }

  if (('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
    return true;
  }

  // include the 'heartz' as a way to have a non matching MQ to help terminate the join
  // https://git.io/vznFH
  var query = ['(', prefixes.join('touch-enabled),('), 'heartz', ')'].join('');
  return mq(query);
}

Здесь они используют нестандартную функцию мультимедийных запросов с touch-enabled экраном, которая, по моему мнению, является довольно странной и плохой практикой. Но эй, в реальном мире, я думаю, это работает. В будущем (когда они будут поддерживаться всеми) эти функции медиа-запросов могут дать вам те же результаты: pointer и hover .

Посмотрите источник, как это делает Modernizr .

Для хорошей статьи, которая объясняет проблемы с обнаружением касания, см .: Stu Cox: вы не можете обнаружить сенсорный экран .


Если вы используете Modernizr , очень легко использовать Modernizr.touch как упоминалось ранее.

Тем не менее, я предпочитаю использовать комбинацию тестов Modernizr.touch и User Agent, чтобы быть в безопасности.

var deviceAgent = navigator.userAgent.toLowerCase();

var isTouchDevice = Modernizr.touch || 
(deviceAgent.match(/(iphone|ipod|ipad)/) ||
deviceAgent.match(/(android)/)  || 
deviceAgent.match(/(iemobile)/) || 
deviceAgent.match(/iphone/i) || 
deviceAgent.match(/ipad/i) || 
deviceAgent.match(/ipod/i) || 
deviceAgent.match(/blackberry/i) || 
deviceAgent.match(/bada/i));

if (isTouchDevice) {
        //Do something touchy
    } else {
        //Can't touch this
    }

Если вы не используете Modernizr, вы можете просто заменить функцию Modernizr.touch выше ('ontouchstart' in document.documentElement)

Также обратите внимание, что тестирование пользовательского агента iemobile даст вам более широкий диапазон обнаруженных мобильных устройств Microsoft, чем Windows Phone .

Также см. Этот вопрос SO


Используя все комментарии выше, я собрал следующий код, который работает для моих нужд:

var isTouch = (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0));

Я тестировал это на iPad, Android (Браузер и Chrome), Blackberry Playbook, iPhone 4s, Windows Phone 8, IE 10, IE 8, IE 10 (Windows 8 с сенсорным экраном), Opera, Chrome и Firefox.

В настоящее время он не работает на Windows Phone 7, и я пока не смог найти решение для этого браузера.

Надеюсь, кто-то найдет это полезным.


Кажется, это работает для меня до сих пор:

//Checks if a touch screen
is_touch_screen = 'ontouchstart' in document.documentElement;

if (is_touch_screen) {
  // Do something if a touch screen
}
else {
  // Not a touch screen (i.e. desktop)
}

Мы пробовали реализацию modernizr, но обнаружение сенсорных событий больше несовместимо (IE 10 имеет события касания на рабочем столе Windows, работает IE 11, потому что у него произошли события касания и добавлен указатель api).

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

Наши исследования говорят, что большинство пользователей рабочего стола перемещаются с помощью мыши над экраном, прежде чем щелкнуть, чтобы мы могли обнаружить их и изменить поведение, прежде чем они смогут щелкнуть или навести что-либо.

Это упрощенная версия нашего кода:

var isTouch = true;
window.addEventListener('mousemove', function mouseMoveDetector() {
    isTouch = false;
    window.removeEventListener('mousemove', mouseMoveDetector);
});

Нет, это невозможно. Отличные ответы даны лишь частично, потому что любой данный метод создает ложные срабатывания и ложные негативы. Даже браузер не всегда знает, присутствует ли сенсорный экран из-за OS API, и факт может измениться во время сеанса браузера, особенно с устройствами типа KVM.

Более подробную информацию см. В этой замечательной статье:

http://www.stucox.com/blog/you-cant-detect-a-touchscreen/

В статье предлагается пересмотреть предположения о том, что вы хотите обнаружить сенсорные экраны, вероятно, они ошибаются. (Я проверил свое приложение для своего приложения, и мои предположения были действительно неправильными!)

Статья заключает:

Для макетов предположим, что у каждого есть сенсорный экран. Пользователи мыши могут использовать большие элементы управления пользовательским интерфейсом намного легче, чем сенсорные пользователи могут использовать небольшие. То же самое касается состояний зависания.

Для событий и взаимодействий предполагайте, что у каждого может быть сенсорный экран. Осуществляйте взаимодействие клавиатуры, мыши и касания друг с другом, не блокируя друг друга.


Похоже, Chrome 24 теперь поддерживает события касания, возможно, для Windows 8. Таким образом, код, отправленный здесь, больше не работает. Вместо того, чтобы пытаться определить, поддерживается ли прикосновение браузером, теперь я привязываю события касания и клика и удостоверяюсь, что вызван только один:

myCustomBind = function(controlName, callback) {

  $(controlName).bind('touchend click', function(e) {
    e.stopPropagation();
    e.preventDefault();

    callback.call();
  });
};

И затем называя это:

myCustomBind('#mnuRealtime', function () { ... });

Надеюсь это поможет !


Практический ответ представляется таким, который рассматривает контекст:

1) Публичный сайт (нет логина)
Назовите интерфейс для совместной работы с обоими параметрами.

2) Вход в систему
Захватите ли перемещение мыши в форме входа и сохраните это в скрытый ввод. Значение передается с учетными данными входа и добавляется в сеанс пользователя, поэтому его можно использовать в течение всего сеанса.

JQuery для добавления только на страницу входа в систему:

$('#istouch').val(1); // <-- value will be submitted with login form

if (window.addEventListener) {
    window.addEventListener('mousemove', function mouseMoveListener(){
        // Update hidden input value to false, and stop listening
        $('#istouch').val(0); 
        window.removeEventListener('mousemove', mouseMoveListener);
    });
} 

(+1 к @Dave Burt и +1 к @Martin Lantzsch по их ответам)


Самая большая «гоча» с попыткой обнаружить прикосновение - это гибридные устройства, которые поддерживают как сенсорный, так и трекпад / мышь. Даже если вы можете правильно определить, поддерживает ли устройство пользовательское устройство, что вам действительно нужно, это определить, какое устройство ввода использует пользователь. Здесь подробно описывается этот вызов и возможное решение здесь .

В принципе, подход к выяснению того, коснулся ли пользователь только экрана или использовал мышь / трекпад, - это зарегистрировать на touchstart событие touchstart и mouseover :

document.addEventListener('touchstart', functionref, false) // on user tap, "touchstart" fires first
document.addEventListener('mouseover', functionref, false) // followed by mouse event, ie: "mouseover"

Действие касания вызовет оба этих события, хотя первый ( touchstart ) всегда будет первым на большинстве устройств. Поэтому, рассчитывая на эту предсказуемую последовательность событий, вы можете создать механизм, который динамически добавляет или удаляет класс can-touch к корню документа, чтобы отразить текущий тип ввода пользователя в данный момент в документе:

;(function(){
    var isTouch = false //var to indicate current input type (is touch versus no touch) 
    var isTouchTimer 
    var curRootClass = '' //var indicating current document root class ("can-touch" or "")
     
    function addtouchclass(e){
        clearTimeout(isTouchTimer)
        isTouch = true
        if (curRootClass != 'can-touch'){ //add "can-touch' class if it's not already present
            curRootClass = 'can-touch'
            document.documentElement.classList.add(curRootClass)
        }
        isTouchTimer = setTimeout(function(){isTouch = false}, 500) //maintain "istouch" state for 500ms so removetouchclass doesn't get fired immediately following a touch event
    }
     
    function removetouchclass(e){
        if (!isTouch && curRootClass == 'can-touch'){ //remove 'can-touch' class if not triggered by a touch event and class is present
            isTouch = false
            curRootClass = ''
            document.documentElement.classList.remove('can-touch')
        }
    }
     
    document.addEventListener('touchstart', addtouchclass, false) //this event only gets called when input type is touch
    document.addEventListener('mouseover', removetouchclass, false) //this event gets called when input type is everything from touch to mouse/ trackpad
})();

Подробнее здесь .


Экстренный объект support jQuery:

jQuery.support.touch = 'ontouchend' in document;

И теперь вы можете проверить его в любом месте, например:

if( jQuery.support.touch )
   // do touch stuff

Я бы не использовал ширину экрана, чтобы определить, является ли устройство сенсорным устройством. Есть сенсорные экраны, намного большие, чем 699 пикселей, подумайте о Windows 8. Navigatior.userAgent может славно переопределить ложные сообщения.

Я бы рекомендовал проверить этот вопрос на Modernizr.

Вы хотите проверить, поддерживает ли устройство сенсорные события или сенсорное устройство. К сожалению, это не одно и то же.


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

Я закончил тем, что использовал:

<script>
$(document).ready(function() {
    var ua = navigator.userAgent;
    function is_touch_device() { 
        try {  
            document.createEvent("TouchEvent");  
            return true;  
        } catch (e) {  
            return false;  
        }  
    }

    if ((is_touch_device()) || ua.match(/(iPhone|iPod|iPad)/) 
    || ua.match(/BlackBerry/) || ua.match(/Android/)) {
        // Touch browser
    } else {
        // Lightbox code
    }
});
</script>

Я также много боролся с различными вариантами определения того, как обнаружить в Javascript, отображается ли страница на сенсорном экране или нет. IMO, на данный момент нет реальной возможности для обнаружения опции должным образом. Браузеры либо сообщают о событиях касания на настольных компьютерах (потому что ОС может быть готова к работе), либо некоторые решения не работают на всех мобильных устройствах.

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

Мое решение состояло в том, чтобы реорганизовать представление, чтобы никакая подсказка не была нужна над кнопкой, и в конце мне не нужно было обнаруживать сенсорное устройство от Javascript с помощью методов, у которых есть свои недостатки .


Рабочий скрипт

Я достиг этого как это;

function isTouchDevice(){
    return true == ("ontouchstart" in window || window.DocumentTouch && document instanceof DocumentTouch);
}

if(isTouchDevice()===true) {
    alert('Touch Device'); //your logic for touch device
}
else {
    alert('Not a Touch Device'); //your logic for non touch device
}

Обновление: Пожалуйста, прочитайте ответ blmstr ниже, прежде чем вытащить всю библиотеку обнаружения объектов в свой проект. Обнаружение фактической поддержки касания является более сложным, и Modernizr охватывает только основной вариант использования.

Modernizr - отличный, легкий способ делать все виды обнаружения функций на любом сайте.

Он просто добавляет классы в элемент html для каждой функции.

Затем вы можете легко ориентировать эти функции в CSS и JS. Например:

html.touch div {
    width: 480px;
}

html.no-touch div {
    width: auto;
}

И Javascript (пример jQuery):

$('html.touch #popup').hide();

$.support.touch ? "true" : "false";




touch