Какой лучший способ обнаружить устройство "сенсорного экрана" с использованием JavaScript?

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

Возможно ли это?

Ответ 1

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

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

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

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

html.touch div {
    width: 480px;
}

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

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

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

Ответ 2

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

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

ОБНОВЛЕНИЕ 1

document.createEvent("TouchEvent") начали возвращать true в последнем Chrome (v. 17). 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 это делает.

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

Ответ 3

Поскольку Modernizr не обнаруживает IE10 на Windows Phone 8/WinRT, простое кросс-браузерное решение:

var supportsTouch = 'ontouchstart' in window || navigator.msMaxTouchPoints;

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

Ответ 4

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

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, и я еще не смог найти решение для этого браузера.

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

Ответ 5

Мне нравится этот:

function isTouchDevice(){
    return typeof window.ontouchstart !== 'undefined';
}

alert(isTouchDevice());

Ответ 6

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

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

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.

Также посмотрите этот ТАК вопрос

Ответ 7

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

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

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

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

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

Ответ 9

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

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

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
}

Ответ 10

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

if (window.addEventListener) {
    var once = false;
    window.addEventListener('touchstart', function(){
        if (!once) {
            once = true;
            // Do what you need for touch-screens only
        }
    });
}

Ответ 11

Это хорошо работает даже в планшетах Windows Surface!!!

function detectTouchSupport {
msGesture = window.navigator && window.navigator.msPointerEnabled && window.MSGesture,
touchSupport = (( "ontouchstart" in window ) || msGesture || window.DocumentTouch &&     document instanceof DocumentTouch);
if(touchSupport) {
    $("html").addClass("ci_touch");
}
else {
    $("html").addClass("ci_no_touch");
}
}

Ответ 12

Я использовал фрагменты кода выше, чтобы определить, касаются ли они, поэтому мои фреймы 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>

Ответ 13

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

В основном подход к выяснению того, коснулся ли пользователь только экран или использовал мышь/трекпад, - это зарегистрировать на странице как событие 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 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
})();

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

Ответ 14

Посмотрите post, он дает действительно хороший фрагмент кода для того, что делать, если сенсорные устройства обнаружены или что делать, если touchstart event называется:

$(function(){
  if(window.Touch) {
    touch_detect.auto_detected();
  } else {
    document.ontouchstart = touch_detect.surface;
  }
}); // End loaded jQuery
var touch_detect = {
  auto_detected: function(event){
    /* add everything you want to do onLoad here (eg. activating hover controls) */
    alert('this was auto detected');
    activateTouchArea();
  },
  surface: function(event){
    /* add everything you want to do ontouchstart here (eg. drag & drop) - you can fire this in both places */
    alert('this was detected by touching');
    activateTouchArea();
  }
}; // touch_detect
function activateTouchArea(){
  /* make sure our screen doesn't scroll when we move the "touchable area" */
  var element = document.getElementById('element_id');
  element.addEventListener("touchstart", touchStart, false);
}
function touchStart(event) {
  /* modularize preventing the default behavior so we can use it again */
  event.preventDefault();
}

Ответ 15

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

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

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

Ответ 16

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

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

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

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

В заключение статьи:

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

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

Ответ 17

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

myCustomBind = function(controlName, callback) {

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

    callback.call();
  });
};

И затем назовем его:

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

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

Ответ 18

Многие из них работают, но требуют либо jQuery, либо линтеры javascript жалуются на синтаксис. Учитывая ваш первоначальный вопрос, вам нужен способ "JavaScript" (не jQuery, не Modernizr) для решения этой проблемы, здесь простая функция, которая работает каждый раз. Это также как можно меньше.

function isTouchDevice() {
    return !!window.ontouchstart;
}

console.log(isTouchDevice());

Еще одно преимущество, которое я упомяну, заключается в том, что этот код не зависит от инфраструктуры и устройств. Наслаждайтесь!

Ответ 19

var isTouchScreen = 'createTouch' in document;

или

var isTouchScreen = 'createTouch' in document || screen.width <= 699 || 
    ua.match(/(iPhone|iPod|iPad)/) || ua.match(/BlackBerry/) || 
    ua.match(/Android/);

будет более тщательной проверкой, я полагаю.

Ответ 20

Я использую:

if(jQuery.support.touch){
    alert('Touch enabled');
}

в jQuery mobile 1.0.1

Ответ 21

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

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

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

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

Ответ 22

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

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

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

Ответ 23

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

Я создал jsFiddle

function isTouchDevice(){
    if(Modernizr.hasEvent('touchstart') || navigator.userAgent.search(/Touch/i) != -1){
         alert("is touch");
            return true;
         }else{
            alert("is not touch");
            return false;
    }
}

Ответ 24

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

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

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

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 по их ответам)

Ответ 25

jQuery v1.11.3

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

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

Помимо этого сообщения и Обнаружение устройств сенсорного экрана с 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 
{

}

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

Ответ 26

Быстрая заметка для тех, кто может быть соблазн написать window.ontouchstart !== undefined → , пожалуйста, используйте микрофонный ответ, так как undefined не является ключевым словом в JavaScript. Большая проблема, если развивается, пишет что-то вроде:

undefined = window.ontouchstart;

Разработчик может сделать undefined все, что угодно, и вы также можете проверить, если window.ontouchstart = myNonExistingWord;

Нет неуважения к тем, кто дал этот ответ: довольно уверен, что я написал это в моем коде тоже;)

Ответ 27

Проблема

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

Сенсорные устройства также запускают mousemove при нажатии.

Решение

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

Протестировано на 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);
}

Ответ 28

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

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

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

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

Ответ 29

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

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

Ответ 30

Когда мышь прикрепляется, можно предположить, что с довольно высокой скоростью (я бы сказал, практически 100%), что пользователь перемещает мышь по крайней мере на небольшое расстояние после того, как страница готова - без щелчка. Механизм ниже определяет это. Если обнаружено, я считаю это признаком отсутствия поддержки касания или, если поддерживается, имеет второстепенное значение, когда мышь используется. Touch-устройство считается, если оно не обнаружено.

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

Грубо, это похоже на это (извините за jQuery, но похоже в чистом Javascript):

var mousedown, first, second = false;
var ticks = 10;
$(document).on('mousemove', (function(e) {
    if(UI.mousechecked) return;
    if(!first) {
        first = e.pageX;
        return;
        }
    if(!second && ticks-- === 0) {
        second = e.pageX;
        $(document).off('mousemove'); // or bind it to somewhat else
        }
    if(first  && second  && first !== second && !mousedown){
        // set whatever flags you want
        UI.hasmouse = true;
        UI.touch = false;
        UI.mousechecked = true;
    }

    return;
}));
$(document).one('mousedown', (function(e) {
    mousedown = true;
    return;
}));
$(document).one('mouseup', (function(e) {
    mousedown = false;
    return;
}));