Я написал подключаемый модуль jQuery для использования как на настольных, так и на мобильных устройствах. Я задавался вопросом, есть ли способ с JavaScript определить, имеет ли устройство сенсорный экран. Я использую jquery-mobile.js для обнаружения событий сенсорного экрана, и он работает на iOS, Android и т.д., Но я также хотел бы написать условные утверждения на основе того, имеет ли пользовательское устройство сенсорный экран.
Возможно ли это?
Обновление: прочитайте ответ blmstr ниже, прежде чем вытащить всю библиотеку обнаружения объектов в свой проект. Обнаружение фактической поддержки касания является более сложным, и Modernizr охватывает только основной вариант использования.
Modernizr - отличный, легкий способ делать все виды обнаружения функций на любом сайте.
Он просто добавляет классы в элемент html для каждой функции.
Затем вы можете легко настроить эти функции в CSS и JS. Например:
html.touch div {
width: 480px;
}
html.no-touch div {
width: auto;
}
И Javascript (пример jQuery):
$('html.touch #popup').hide();
Вы пытались использовать эту функцию? (Это то же самое, что использовалось в Modernizr.)
function is_touch_device() {
try {
document.createEvent("TouchEvent");
return true;
} catch (e) {
return false;
}
}
UPDATE:
document.createEvent("TouchEvent")
начали возвращать true
в последнем хроме (v. 17). Modernizr обновил это некоторое время назад. Проверьте версию Modernizr здесь.
Обновите свою функцию следующим образом:
function is_touch_device() {
return 'ontouchstart' in window;
}
UPDATE:
Я обнаружил, что вышеописанное не работает на 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
};
UPDATE
'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
};
Или Modernizr обновили свои тесты, чтобы включить некоторую магию медиа-запросов CSS, поэтому вы можете попробовать это.
Но все они далеки от совершенства. Для хорошей статьи, которая объясняет проблемы с сенсорным обнаружением, см. Stu Cox: вы не можете обнаружить сенсорный экран.
true
либо false
. Вы можете прочитать больше об этом здесь: stackoverflow.com/questions/4686583/…
Поскольку Modernizr не обнаруживает IE10 на Windows Phone 8/WinRT, простое кросс-браузерное решение:
var supportsTouch = 'ontouchstart' in window || navigator.msMaxTouchPoints;
Вам нужно только один раз проверить, как устройство не будет внезапно поддерживать или не поддерживать сенсорный интерфейс, поэтому просто сохраните его в переменной, чтобы вы могли использовать его несколько раз более эффективно.
return !!('ontouchstart' in window) || !!('msmaxtouchpoints' in window.navigator);
(объединить оба ответа) Отлично работает и в IE10!
Используя все комментарии выше, я собрал следующий код, который работает для моих нужд:
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 isTouchDevice(){
return typeof window.ontouchstart !== 'undefined';
}
alert(isTouchDevice());
function isTouchDevice(){ return (window.ontouchstart !== undefined); }
var isTouch = 'ontouchstart' in window;
Однако это не работает с последним Chrome (v31), var isTouch = 'createTouch' in window.document;
все еще работает.
Если вы используете 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
.
Мы пробовали реализацию modernizr, но обнаружение сенсорных событий больше несовместимо (IE 10 имеет события касания на рабочем столе Windows, IE 11 работает, потому что у него произошли события касания и добавлен указатель api).
Итак, мы решили оптимизировать сайт как сенсорный сайт, пока мы не знаем, какой тип ввода у пользователя есть. Это более надежно, чем любое другое решение.
В наших исследованиях говорится, что большинство пользователей рабочего стола перемещаются с помощью мыши над экраном, прежде чем щелкнуть, чтобы мы могли обнаружить их и изменить поведение, прежде чем они смогут щелкнуть или навести что-либо.
Это упрощенная версия нашего кода:
var isTouch = true;
window.addEventListener('mousemove', function mouseMoveDetector() {
isTouch = false;
window.removeEventListener('mousemove', mouseMoveDetector);
});
Я достиг этого так:
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
}
Есть что-то лучше, чем проверка, если у них есть сенсорный экран, чтобы проверить, используют ли они его, плюс, что легче проверить.
if (window.addEventListener) {
var once = false;
window.addEventListener('touchstart', function(){
if (!once) {
once = true;
// Do what you need for touch-screens only
}
});
}
Это хорошо работает даже в планшетах 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");
}
}
Я использовал фрагменты кода выше, чтобы определить, касаются ли они, поэтому мои фреймы 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>
/iPhone|iPod|iPad|Android|BlackBerry/
?
Самая большая "гоча" с попыткой обнаружить прикосновение - это гибридные устройства, которые поддерживают как сенсорный, так и трекпад/мышь. Даже если вы можете правильно определить, поддерживает ли пользовательское устройство касание, что вам действительно нужно, это определить, какое устройство ввода использует пользователь. Там детальная запись этой проблемы и возможное решение здесь.
В основном подход к выяснению того, коснулся ли пользователь только экран или использовал мышь/трекпад, - это зарегистрировать на странице как событие 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
})();
Подробнее здесь.
Нет, это невозможно. Отличные ответы даны лишь частично, потому что любой данный метод создает ложные срабатывания и ложные негативы. Даже браузер не всегда знает, присутствует ли сенсорный экран из-за OS API, и факт может измениться во время сеанса браузера, особенно с устройствами типа KVM.
См. дополнительную информацию в этой замечательной статье:
http://www.stucox.com/blog/you-cant-detect-a-touchscreen/
В статье предлагается пересмотреть предположения о том, что вы хотите обнаружить сенсорные экраны, вероятно, они ошибаются. (Я проверил свое приложение для своего приложения, и мои предположения были действительно неправильными!)
В заключение статьи:
Для макетов предположим, что у каждого есть сенсорный экран. Пользователи мыши могут использовать большие пользовательские интерфейсы намного легче, чем сенсорные пользователи могут использовать небольшие из них. То же самое касается состояний зависания.
Для событий и взаимодействий предполагайте, что у каждого может быть сенсорный экран. Осуществляйте взаимодействие клавиатуры, мыши и касания друг с другом, не блокируя друг друга.
Я бы не использовал ширину экрана, чтобы определить, является ли устройство сенсорным устройством. Есть сенсорные экраны, намного большие, чем 699 пикселей, подумайте о Windows 8. Navigatior.userAgent может славно переопределить ложные сообщения.
Я бы рекомендовал проверить эту проблему на Modernizr.
Вы хотите проверить, поддерживает ли устройство сенсорные события или сенсорное устройство. К сожалению, это не то же самое.
Посмотрите 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();
}
Похоже, что Chrome 24 теперь поддерживает события касания, возможно, для Windows 8. Таким образом, код, отправленный здесь, больше не работает. Вместо того, чтобы пытаться определить, поддерживается ли прикосновение браузером, теперь я привязываю события касания и клика и удостоверяюсь, что вызван только один:
myCustomBind = function(controlName, callback) {
$(controlName).bind('touchend click', function(e) {
e.stopPropagation();
e.preventDefault();
callback.call();
});
};
И затем назовем его:
myCustomBind('#mnuRealtime', function () { ... });
Надеюсь, это поможет!
Благодаря гибридным устройствам, использующим комбинацию сенсорных и мышечных входов, вам необходимо динамически изменять состояние/переменную, которая контролирует, должна ли часть кода работать, если пользователь является сенсорным пользователем или нет.
Сенсорные устройства также запускают mousemove
при нажатии.
touchstart
, затем установите значение true.Протестировано в Safari iOS и Chrome для Android.
Примечание: не на 100% уверены в указателях-событиях для MS Surface и т.д.
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 < 10) {
isUsingTouch = false;
document.removeEventListener('mousemove', mousemoveHandler);
}
time = now;
}
})();
// add listeners
if (supportsTouch) {
document.addEventListener('touchstart', touchHandler);
} else if (navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0) {
document.addEventListener('pointerdown', touchHandler);
}
Быстрая заметка для тех, кто может быть соблазн написать window.ontouchstart !== undefined
→ , пожалуйста, используйте микрофонный ответ, так как undefined
не является ключевым словом в JavaScript. Большая проблема, если развивается, пишет что-то вроде:
undefined = window.ontouchstart;
Разработчик может сделать undefined все, что угодно, и вы также можете проверить, если window.ontouchstart = myNonExistingWord;
Нет неуважения к тем, кто дал этот ответ: довольно уверен, что я написал это в моем коде тоже;)
undefined
является неизменным с ES5 (2009).
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
{
}
Примечание. Существуют и другие селектора...
Практический ответ представляется таким, который рассматривает контекст:
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 по их ответам)
Вы можете установить модернизатор и использовать простое событие касания. Это очень эффективно и работает на каждом устройстве, на котором я тестировал его, включая поверхность окна!
Я создал 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;
}
}
Я также много боролся с различными опциями о том, как обнаружить в Javascript, отображается ли страница на сенсорном экране или нет. IMO, на данный момент нет реальной возможности для обнаружения опции должным образом. Браузеры сообщают о событиях касания на настольных компьютерах (потому что ОС может быть готова к работе), или некоторые решения не работают на всех мобильных устройствах.
В конце концов, я понял, что с самого начала я следил за неправильным подходом: Если бы моя страница выглядела одинаково на сенсорных и не сенсорных устройствах, мне, возможно, не пришлось бы беспокоиться об обнаружении свойства вообще: Мой сценарий состоял в том, чтобы деактивировать всплывающие подсказки над кнопками на сенсорных устройствах, поскольку они приводят к двойным нажатием, где я хотел, чтобы один кран активировал кнопку.
Мое решение состояло в рефакторе в представлении, чтобы никакая подсказка не понадобилась над кнопкой, и в конце мне не нужно было обнаруживать сенсорное устройство из Javascript с помощью методов, которые все имеют свои недостатки.
Все поддерживаемые браузеры, кроме Firefox для рабочего стола, всегда TRUE, потому что Firefox для настольных ПК поддерживает гибкий дизайн для разработчика, даже вы нажимаете Touch-Button или нет!
Я надеюсь, что Mozilla установит это в следующей версии.
Я использую рабочий стол Firefox 28.
function isTouch()
{
return !!("ontouchstart" in window) || !!(navigator.msMaxTouchPoints);
}
true
:(
Я использую:
if(jQuery.support.touch){
alert('Touch enabled');
}
в jQuery mobile 1.0.1
Это так просто, если вы тестируете, что touchstart поддерживается в документе document.documentElement
var x = 'touchstart' in document.documentElement;
console.log(x)
// return true if is supported
// else return false
$.support.touch ? "true" : "false";
Вы можете использовать следующий код:
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.
Когда мышь прикрепляется, можно предположить, что с довольно высокой скоростью (я бы сказал, практически 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;
}));
Кажется, это работает для меня до сих пор:
//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)
}
Многие из них работают, но либо требуют jQuery, либо javascript linters жалуются на синтаксис. Учитывая, что ваш первоначальный вопрос задает способ "JavaScript" (а не jQuery, а не Modernizr), это простая функция, которая работает каждый раз. Это также минимально, как вы можете получить.
function isTouchDevice() {
return window.ontouchstart !== undefined;
}
console.log(isTouchDevice());
Последнее пособие, о котором я упоминаю, заключается в том, что этот код является агностиком для платформы и устройства. Наслаждайтесь!
Экстент jQuery support
объект:
jQuery.support.touch = 'ontouchend' in document;
И теперь вы можете проверить его в любом месте, например:
if( jQuery.support.touch )
// do touch stuff
var isTouchScreen = 'createTouch' in document;
или
var isTouchScreen = 'createTouch' in document || screen.width <= 699 ||
ua.match(/(iPhone|iPod|iPad)/) || ua.match(/BlackBerry/) ||
ua.match(/Android/);
будет более тщательной проверкой, я полагаю.
ua
ссылается на navigator.userAgent
. Также обнаружение по ширине экрана может дать ложный результат, если кто-то открывает браузер в не полноэкранном режиме.
Хотя это только в альфах, стоит проверить jquery mobile framework. Он будет нормализовать эти типы событий в мобильных браузерах. Возможно, посмотрите, что они делают. Я предполагаю, что jquery-mobile.js - это нечто иное, чем эта структура.
этот способ работает для меня, он ждет первого взаимодействия с пользователем, чтобы убедиться, что они находятся на сенсорных устройствах.
var touchEnabled = false;
$(document.body).one('touchstart',
function(e){
touchEnabled=true;
$(document.documentElement).addClass("touch");
// other touch related init
//
}
);