Как лучше всего обнаружить устройство с «сенсорным экраном» с помощью JavaScript?

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

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

375
задан Mark Amery 15 October 2013 в 16:24
поделиться

36 ответов

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

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

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

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

html.touch div {
    width: 480px;
}

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

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

$('html.touch #popup').hide();
137
ответ дан Community 15 October 2013 в 16:24
поделиться

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

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

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

1
ответ дан Michael 15 October 2013 в 16:24
поделиться

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

Я создал 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;
    }
}
1
ответ дан Dan Beaulieu 15 October 2013 в 16:24
поделиться

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

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

1
ответ дан prograhammer 15 October 2013 в 16:24
поделиться

Это, кажется, работает хорошо для меня до сих пор:

//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)
}
0
ответ дан Lewis James-Odwin 15 October 2013 в 16:24
поделиться

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

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

И теперь вы можете проверить его где угодно, например:

if( jQuery.support.touch )
   // do touch stuff
0
ответ дан vsync 15 October 2013 в 16:24
поделиться

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

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

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

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

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

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

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

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

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

0
ответ дан kenorb 15 October 2013 в 16:24
поделиться
var isTouchDevice =
    (('ontouchstart' in window) ||
    (navigator.MaxTouchPoints > 0) ||
    (navigator.msMaxTouchPoints > 0));
if(!isTouchDevice){
    /* Code for touch device /*
}else{
    /* Code for non touch device */
}

Веселись!

0
ответ дан Farhad Sakhaei 15 October 2013 в 16:24
поделиться
$.support.touch ? "true" : "false";
0
ответ дан Floern 15 October 2013 в 16:24
поделиться

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

var touchEnabled = false;
$(document.body).one('touchstart',
    function(e){
        touchEnabled=true;
        $(document.documentElement).addClass("touch");
        // other touch related init 
        //
    }
);
-3
ответ дан Bagus Budiarto 15 October 2013 в 16:24
поделиться

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

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

alert(isTouchDevice());
20
ответ дан micnic 15 October 2013 в 16:24
поделиться

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

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

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

34
ответ дан David 15 October 2013 в 16:24
поделиться

Я использую:

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

в jQuery mobile 1.0.1

1
ответ дан Mark 15 October 2013 в 16:24
поделиться

Если вы используете 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.

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

17
ответ дан Community 15 October 2013 в 16:24
поделиться

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

undefined = window.ontouchstart;

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

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

0
ответ дан Raymond Naseef 15 October 2013 в 16:24
поделиться

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

Я добился этого вот так;

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
}
9
ответ дан Aamir Shahzad 15 October 2013 в 16:24
поделиться

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

$(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();
}
3
ответ дан Safran Ali 15 October 2013 в 16:24
поделиться

С момента появления интерактивных медиа-функций вы просто можете сделать:

if(window.matchMedia("(any-pointer: coarse)").matches) {
    // touchscreen
}

https://www.w3.org/TR / mediaqueries-4 / # descdef-медиа-любой-указатель

7
ответ дан Blackbam 15 October 2013 в 16:24
поделиться
var isTouchScreen = 'createTouch' in document;

или

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

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

1
ответ дан HoLyVieR 15 October 2013 в 16:24
поделиться

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

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

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

117
ответ дан Matt Stow 15 October 2013 в 16:24
поделиться

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

-2
ответ дан ScottE 15 October 2013 в 16:24
поделиться

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

myCustomBind = function(controlName, callback) {

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

    callback.call();
  });
};

И затем вызываю его:

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

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

2
ответ дан wizmagister 15 October 2013 в 16:24
поделиться

Этот работает хорошо даже в планшетах 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");
}
}
6
ответ дан Sathiyamoorthy 15 October 2013 в 16:24
поделиться

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

РЕДАКТИРОВАТЬ Этот подход может не подходить для всех целей. Он может использоваться для управления функциональностью, которая активируется на основе взаимодействия с пользователем на загруженной странице, например, в программе просмотра изображений. Приведенный ниже код также оставит событие 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;
}));
0
ответ дан cglow 15 October 2013 в 16:24
поделиться

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

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

ОБНОВЛЕНИЕ 1

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

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

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

ОБНОВЛЕНИЕ 2

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

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.

Проверьте источник того, как Модернизр делает это .

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

614
ответ дан bolmaster2 15 October 2013 в 16:24
поделиться

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

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

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

3
ответ дан hybrid 15 October 2013 в 16:24
поделиться

Проблема

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

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

Решение

  1. Предположим, что прикосновение ложно при нагрузке.
  2. Подождите, пока не сработает событие touchstart, затем установите для него значение true.
  3. Если сенсорный запуск был запущен, добавьте обработчик перемещения мыши.
  4. Если время между двумя событиями перемещения мыши было менее 20 мс, предположим, что они используют мышь в качестве входных данных. Удалите событие, так как оно больше не нужно, и mousemove - дорогостоящее событие для мышиных устройств.
  5. Как только сенсорный запуск запускается снова (пользователь вернулся к использованию сенсорного ввода), для переменной устанавливается значение true. И повторите процесс, чтобы он определялся динамично. Если каким-то чудом мышиный ход сработал дважды при прикосновении до абсурда быстро (в моем тестировании это практически невозможно сделать в течение 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);
}
1
ответ дан frosty 15 October 2013 в 16:24
поделиться

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

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

console.log(isTouchDevice());

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

2
ответ дан Michael Cole 15 October 2013 в 16:24
поделиться

Я использовал фрагменты кода выше, чтобы определить, есть ли касание, поэтому мои фреймворки в fancybox будут отображаться на настольных компьютерах, а не на ощупь. Я заметил, что 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>
4
ответ дан Loved 15 October 2013 в 16:24
поделиться

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

if (window.addEventListener) {
    var once = false;
    window.addEventListener('touchstart', function(){
        if (!once) {
            once = true;
            // Do what you need for touch-screens only
        }
    });
}
9
ответ дан Ivan Castellanos 15 October 2013 в 16:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: