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


416

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

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


это лучший способ var x = 'touchstart' в document.documentElement; console.log (x) // вернуть true, если поддерживается // иначе вернуть false
Risa__B

Почему этот поток защищен, если новые технологии все еще появляются?
Энди Хоффман

Ответы:


139

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

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

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

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

html.touch div {
    width: 480px;
}

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

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

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

88
Модернизр не тестирует на сенсорные экраны. Он проверяет наличие сенсорных событий в браузере. См. Раздел «Разные тесты» в документации: modernizr.com/docs/#features-misc
Гарри Лав

1
Вы также можете выполнить JS-тест на наличие сенсорных событий, если (Modernizr.touch) {/ * do touch stuff /} else {/ fine, not * /}
Анатолий Г

7
Кстати, с момента выхода Windows 8 Modernizr неправильно возвращает все браузеры моего компьютера как сенсорные.
Антон

3
Обновление: ответ blmstr лучше и является чистым решением Javascript.
Алан Кристофер Томас

1
Если Modernizr.touchнеожиданно возвращается undefined, у вас может быть настроенный Modernizr (вы можете выбирать) без поддержки обнаружения сенсорных событий.
Хенрик Н

680

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

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

console.log(is_touch_device());

ОБНОВЛЕНИЕ 1

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

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

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

console.log(is_touch_device1());

ОБНОВЛЕНИЕ 2

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

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

console.log(is_touch_device2());

ОБНОВЛЕНИЕ 3

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

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

console.log(is_touch_device3());

ОБНОВЛЕНИЕ 2018

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

function is_touch_device4() {
    
    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);
}

console.log(is_touch_device4());

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

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

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


20
Двойной взрыв приводит значение к логическому значению, заставляя функцию возвращать trueили false. Вы можете прочитать больше об этом здесь: stackoverflow.com/questions/4686583/…
Роб Флаэрти

2
Это не работает с Opera Mobile 10 или Internet Explorer Mobile 6 (Windows Mobile 6.5).
doubleJ

17
Двойное НЕ (!!) является излишним, поскольку inоператор уже вычисляет логическое значение.
Стив

11
'onmsgesturechange'оценивает истину даже в несенсорных устройствах (ПК). window.navigator.msMaxTouchPointsкажется более точным. Нашел это здесь .
Стив

6
В IE10 на Windows 8 он оценивается как истинный, хотя на моем экране нет сенсорных датчиков. Я обновил свой старый ноутбук с Windows 7 до Windows 8.
Pwner

120

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

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

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


3
«onmsgesturechange» в окне также обнаруживает «настольный» IE10 на не сенсорных устройствах, поэтому это не надежный метод определения касания.
Мэтт Стоу

6
Этот ответ должен был быть принят, так как он самый лучший, самый простой и актуальный. Я полагаю, что в функции это будет более логичным: return !!('ontouchstart' in window) || !!('msmaxtouchpoints' in window.navigator);(объединить оба ответа) Отлично работает и в IE10!
Yeti

Это должен быть принятый ответ. 'onmsgesturechange' in windowвозвращает true на рабочем столе IE10, даже когда сенсорный возможен
Сэм Торнтон

6
Все, что вам нужно:function isTouchDevice() { return 'ontouchstart' in window || !!(navigator.msMaxTouchPoints);}
GFoley83

1
Даже предложение GFoleys 'ontouchstart' в окне || !! (navigator.msMaxTouchPoints); возвращает Chals положительный в Chrome 30 dev фев 2014.
Том Андерсен

37

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

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

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


Есть ли причина, по которой вы не можете использовать: function is_touch_device () {return !! ('ontouchstart' в окне) || !! ('msmaxtouchpoints' в навигаторе); };
Сидональдсон

использование функции будет работать, но я обычно предпочитаю использовать метод переменных, описанный выше, поэтому он проверяется только один раз и быстрее, когда я проверяю позже в своем коде. Также я обнаружил, что мне нужно проверить, было ли значение msMaxTouchPoints больше 0, так как IE 10 в Windows 8 без сенсорного экрана возвращал 0 как msMaxTouchPoints.
Дэвид

возвращается trueна моем Firefox 32 на Windows 7 :(
vsync

Firefox 33 и 33.1 в Windows 8 оба отображают false в моей системе. Если вы обновите Firefox до последней версии, он все равно вернет true? Возможно, на вашем компьютере установлено устройство, из-за которого Firefox может ошибочно думать, что на вашем компьютере есть сенсорный экран?
Дэвид

>>> 'ontouchstart' в окне >>> true FF 51.0.1 в Ubuntu
Рави Гадия

26

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

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

https://www.w3.org/TR/mediaqueries-4/#descdef-media-any-pointer

Обновление (из-за комментариев): вышеупомянутое решение состоит в том, чтобы определить, является ли «грубый указатель» - обычно сенсорный экран - основным устройством ввода. Если вы хотите определить, есть ли у устройства, например, мыши, сенсорный экран, вы можете использоватьany-pointer: coarse вместо этого.

Для получения дополнительной информации посмотрите здесь: Обнаружение, что браузер не имеет мыши и только для касания


3
Это, безусловно, лучшее решение, спасибо! Хотя я бы порекомендовал использовать, так (pointer: coarse)как вы, скорее всего, ориентируетесь только на первичный вход. Может использоваться в производстве, поскольку некоторые неподдерживающие браузеры предназначены только для настольных компьютеров. Об этом есть отличная статья о трюках css .
Фабиан фон Эллертс

2
Это единственное проверенное мной решение, которое работает в любой ситуации. Спасибо!
kaiserkiwi

20

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

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

alert(isTouchDevice());

12
Нет необходимости использовать троичное выражение для возврата логического значения. Просто используйте выражение, чтобы вернуть логическое значение. function isTouchDevice(){ return (window.ontouchstart !== undefined); }
Тим Вермален

1
Вы также можете просто использовать: var isTouch = 'ontouchstart' in window;однако это не работает с последним Chrome (v31), var isTouch = 'createTouch' in window.document;все еще работает.
Оливье

2
Как уже упоминалось в комментариях к ранее принятому вопросу. «Modernizr не проверяет сенсорные экраны. Он проверяет наличие сенсорных событий в браузере». Технически ваша функция имеет hasTouchEvents (), а не isTouchDevice ()
hexalys

Обратите внимание, что только при тестировании аналогичных методов touchstartSurface не сможет распознать сенсорное устройство, поскольку IE использует pointerсобытия.
CookieMonster

1
Возможно, @Nis был прав, но в Firefox 39 он правильно возвращает false.
Дан Даскалеску

17

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

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


8
Множество бонусных баллов за «сделай что-нибудь обидчивое» и «не прикасайся к этому»
Ли Саксон

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

1
этого должно быть достаточно:/(iphone|ipod|ipad|android|iemobile|blackberry|bada)/.test(window.navigator.userAgent.toLowerCase())
Цезарсоль

Любая причина, чтобы строчные буквы или сделать сопоставление без учета регистра? Когда «iOS», «Android» или «IEMobile» будут использовать другой корпус?
Хенрик N

14

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

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

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

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

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

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

1
Да, вы правы, но это очень сложно. В лучшем случае ваше приложение предназначено для использования любым контроллером ввода, и ему все равно, есть ли у пользователя сенсорный экран, мышь, клавиатура или все вместе.
Мартин Ланцш

1
Поведение пользователя более ценно, чем реальная информация о том, какое устройство имеет пользователь. Когда вы знаете, что у пользователя есть мышь, сенсорный экран и клавиатура - что тогда? Обработайте поведение (перемещение мышью, касание, нажатие клавиши и т. Д.). Пользователи могут изменять свой тип ввода во время выполнения, это очень сложная проблема, когда вы разрабатываете реальное приложение, которое используется с 8 по 5 без перезагрузки.
Мартин Ланцш

2
+1 Прагматично это лучший ответ для меня. Например, у меня есть датагрид. Эти сетки данных покажут «иконку редактирования», которую нужно коснуться для редактирования, или контекстное меню для дополнительных параметров. Если обнаружено движение мыши, я удаляю значок (экономит место на сетке), и пользователи могут дважды щелкнуть или щелкнуть правой кнопкой мыши.
программер

3
хром на сенсорных устройствах иногда вызывает движение мыши
pstanton

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
}

не обнаруживает планшет с поверхностью Windows
Дэн Болье

@DanBeaulieu, можете ли вы быть конкретным для устройства, потому что у меня есть Windows Phone, для которого он работает нормально, также я использовал его в своем приложении, которое является QA: ED, я еще раз проверим его и обновлю ответ. Приносим извинения за неудобства
Аамир Шахзад

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

Это правильно сообщалось о Non-Touch на моем компьютере с Windows 7 и касании на ноутбуке с Windows 8 с сенсорным экраном и телефоном Android 4.4 MotoX.
Клей Николс

Дает ложный положительный результат в Chrome (46) на моем Mac
Патрик Фабрициус

9

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

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

6

Этот работает хорошо даже в планшетах 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");
}
}

4

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

Не могли бы вы объяснить, почему вы не используете один вызов для сопоставления с одним регулярным выражением /iPhone|iPod|iPad|Android|BlackBerry/?
user907860

Opera Mini выполняет рендеринг на серверах Opera, а не на самом устройстве, так что это довольно странно.
Bluesmoon

4

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

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

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


3

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

$(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

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

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

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


3

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

Смотрите подробности в этой прекрасной статье:

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

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

В статье делается вывод:

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

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


3

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

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

console.log(isTouchDevice());

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


function isTouchScreen() { return window.matchMedia('(hover: none)').matches;}Это сработало для меня, так что я здесь добавляю вклад в этот ответ, так как я также ожидал ванильного потока JS, когда Google привел меня сюда.
Даниэль Лаведонио де Лима

2

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

myCustomBind = function(controlName, callback) {

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

    callback.call();
  });
};

А потом называет это:

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

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


1
Связанная тема, stackoverflow.com/questions/12566306/…
Air

2

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

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

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

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

это все еще версия 32.0, и они еще не исправили это! невменяемый. почему это не может быть переключаемым ?? Это всегда возвращает true:(
vsync

2

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» событие, или любое другое подобное событие , связанное со штрихами. В данном случае это элемент гиперссылки «а».

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

/* unvisited link */
a:link 
{

}

/* visited link */
a:visited 
{

}

/* mouse over link */
a:hover 
{

}

/* selected link */
a:active 
{

}

Примечание: есть и другие селекторы ...


1
var isTouchScreen = 'createTouch' in document;

или

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

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


3
Было бы хорошо отметить, что uaотносится к navigator.userAgent. Также обнаружение по ширине экрана может дать ложный результат, если кто-то открывает браузер в не полноэкранном режиме.
HoLyVieR


1

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

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

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


1

Вы можете установить модернизатор и использовать простое сенсорное событие. Это очень эффективно и работает на каждом устройстве, которое я тестировал, включая поверхность 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;
    }
}

3
Добро пожаловать на ТАК! Код сам по себе (например, код без комментариев) редко представляет собой ответ. Вы можете улучшить этот ответ, добавив пояснение к фрагменту.
ebarr

1

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

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

Проблема

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

Сенсорные устройства также стреляют 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);
}

1

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

const isTouchDevice = () => {
  const prefixes = ['', '-webkit-', '-moz-', '-o-', '-ms-', ''];
  const mq = query => window.matchMedia(query).matches;

  if (
    'ontouchstart' in window ||
    (window.DocumentTouch && document instanceof DocumentTouch)
  ) {
    return true;
  }
  return mq(['(', prefixes.join('touch-enabled),('), 'heartz', ')'].join(''));
};

Подсказка : безусловно,isTouchDeviceпросто возвращаетbooleanзначения.


0

Объем supportобъекта jQuery :

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

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

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

0

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

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

Когда мышь присоединена, можно предположить с довольно высокой скоростью (я бы сказал, практически 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;
}));
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.