Виявлення того, що у веб-переглядачі немає миші та є лише сенсорним


149

Я розробляю веб-сторінку (не веб-сайт зі сторінками цікавого тексту) з дуже різним інтерфейсом для дотику (ваш палець приховує екран при натисканні) та миші (значною мірою спирається на попередній перегляд наведення курсора). Як я можу виявити, що мій користувач не має миші, щоб представити йому правильний інтерфейс? Планую залишити вимикач для людей як з мишкою, так і з дотиком (як у деяких ноутбуках).

Можливість сенсорних подій у веб-переглядачі насправді не означає, що користувач використовує сенсорний пристрій (наприклад, Modernizr не вирізає його). Код, який правильно відповідає на запитання, повинен повернути помилкове значення, якщо у пристрої є миша, правда - інакше. Для пристроїв, які користуються мишею та дотиком, він повинен повертати помилкове значення (не торкатися лише)

Як бічна примітка, мій сенсорний інтерфейс також може бути придатним для пристроїв, які працюють лише на клавіатурі, тому я більше не вистачаю миші.

Щоб зрозуміти необхідність, ось API, який я хочу реалізувати:

// Level 1


// The current answers provide a way to do that.
hasTouch();

// Returns true if a mouse is expected.
// Note: as explained by the OP, this is not !hasTouch()
// I don't think we have this in the answers already, that why I offer a bounty
hasMouse();

// Level 2 (I don't think it's possible, but maybe I'm wrong, so why not asking)

// callback is called when the result of "hasTouch()" changes.
listenHasTouchChanges(callback);

// callback is called when the result of "hasMouse()" changes.
listenHasMouseChanges(callback);


Я думаю, вам потрібно переосмислити свій дизайн, якщо ви хочете, щоб одна програма була застосовна як для настільних пристроїв, так і для мобільних пристроїв / сенсорних технологій, але для них по-різному. Я не думаю, що на даний момент ви насправді можливі, оскільки швидкий пошук в Google "миші для виявлення javascript" показує один помірно корисний пост на quirksmode.org для виявлення різних станів миші (клацання, позиція, тощо), але ZERO визначає, чи існує миша чи ні.
davethegr8

24
Можливо, це тому, що Google не допоміг, що я його тут запитав.
nraynaud

2
Ви спробували документ мишіентера з jquery? $ (документ) .mouseenter (функція (e) {alert ("миша");});
Parag Gajjar

4
Після розгляду майже десятка багатообіцяючих проспектів лише для відхилення кожної з них протягом декількох хвилин, це питання викликає у мене досить чудові бондери.
Джордан Грей

Відповіді:


65

Основна проблема полягає в тому, що у вас є такі різні класи пристроїв / випадків використання:

  1. Миша та клавіатура (настільний)
  2. Лише торкніться (телефон / планшет)
  3. Миша, клавіатура та сенсорний (торкайтеся ноутбуків)
  4. Дотик та клавіатура (клавіатура Bluetooth на планшеті)
  5. Лише миша (вимкнено користувач / налаштування перегляду)
  6. Тільки клавіатура (вимкнено користувач / налаштування перегляду)
  7. Торкніться миші (тобто, наведіть курсор миші на ручку Galaxy Note 2)

Що ще гірше - це те, що можна переходити з деяких з цих класів до інших (підключається миша, підключається до клавіатури), або користувач може ЗАТВЕРДЖУВАТИсь на звичайному ноутбуці, поки не дотягнеться і не торкнеться екрана.

Ви вірно вважаєте, що присутність конструкторів подій у браузері не є гарним способом просуватися вперед (і це дещо непослідовно). Крім того, якщо ви відстежуєте дуже конкретну подію або намагаєтесь виключити кілька класів вище, використання самих подій не є повним доказом.

Наприклад, скажіть, ви виявили, що користувач випромінював справжній рух миші (не той хибний з подій дотику, див Http://www.html5rocks.com/en/mobile/touchandmouse/ ).

Тоді що?

Увімкнено стилі наведення курсора? Ви додали більше кнопок?

У будь-якому випадку ви збільшуєте час на скло, тому що вам доведеться чекати, коли подія загориться.

Але тоді, що станеться, коли ваш благородний користувач вирішить захотіти відключити його від миші та піти на повну контактну позицію?

У формі кулі, цитуючи stucox за посиланням https://github.com/Modernizr/Modernizr/isissue/869#issuecomment-15264101

  • Ми хочемо виявити наявність миші
  • Ae, ймовірно, не може виявити до початку події
  • Таким чином, ми виявляємо, якщо миша була використана в цьому сеансі - це не буде відразу від завантаження сторінки
  • Ми, мабуть, також не можемо виявити, що немає миші - це було б невизначено до істинного (я думаю, це має більше сенсу, ніж встановити його як помилкове, поки не буде доведено)
  • І ми, мабуть, не можемо виявити, якщо миша відключена в середині сеансу - це буде не відрізняти від користувача, який просто відмовився від своєї миші

Зворотний бік: браузер НЕ знає, коли користувач підключає мишу / підключається до клавіатури, але не виставляє її на JavaScript.

Це має призвести до наступного:

Відстеження поточних можливостей певного користувача є складним, ненадійним та сумнівним достоїнством

Ідея про прогресивне вдосконалення тут досить добре застосовується. Створіть досвід, який працює безперебійно, незалежно від контексту користувача. Потім зробіть припущення на основі функцій браузера / медіа-запитів, щоб додати функціонал, який буде відносним у передбачуваному контексті. Наявність миші - це лише один із безлічі способів, коли різні користувачі на різних пристроях переживають ваш веб-сайт. Створіть щось із заслугою на своєму ядрі та не переживайте надто про те, як люди натискають кнопки.


3
чудова відповідь. Сподіваємось, у користувача завжди є екран! Я думаю, що є сенс побудувати інтерфейс, де це пристосовано до поточного режиму взаємодії користувача. На сенсорному ноутбуці має сенс налаштувати додаток (тобто такі :hoverелементи і подібні речі), коли користувач переходить з миші на дотик. Здається, малоймовірно, що користувач наразі використовує клавішу миші + touch в той самий час (я маю на увазі, що це комунально, це як 2 миші, підключені до одного комп’ютера хахаха)
Себастьян Лорбер

@SebastienLorber - ненавиджу порушувати це вам, але користувачі не завжди мають екран. ( Чи можливо за допомогою javascript виявити, чи читач екрану працює на користувальницькій машині? )
ashleedawg

57

Як щодо прослуховування події в русі миші на документі. Тоді, поки ви не почуєте цю подію, ви припускаєте, що пристрій має сенсорний або клавіатурний режим.

var mouseDetected = false;
function onMouseMove(e) {
  unlisten('mousemove', onMouseMove, false);
  mouseDetected = true;
  // initializeMouseBehavior();
}
listen('mousemove', onMouseMove, false);

(Де listenі unlistenделегувати до addEventListenerабоattachEvent якщо це доречно.)

Сподіваємось, це не призведе до занадто великого візуального злому, воно буде смоктати, якщо вам потрібні масштабні перепланування на основі режиму ...


2
Це гарна ідея, але, на жаль, затримка відповіді зробить її непридатною, коли користувальницький інтерфейс програми залежить від того, чи доступна миша. Це особливо вірно, якщо програма може бути заграмована, тому події миші вдарять її лише у випадку, якщо миша пересувається над самою
рамкою

7
Це може спрацювати, якщо програма запуститься із екрану заставки та кнопки «продовжити». Якщо миша рухається до першої події в місті, тоді у вас є миша. Це не вдасться лише в тому випадку, якщо кнопка, що завантажується безпосередньо під мишею, і користувач має дуже стійку руку (потрібно навіть підібрати 1 піксель).
SpliFF

49
хороша ідея, але, здається, не працює в нашому тестуванні . iPad викликає цю подію.
Джефф Етвуд

3
@JeffAtwood, що ти нарешті робив у своїй справі?
Майкл Харен

2
iPad, безумовно, запускає подію, що рухається мишею, безпосередньо перед самим заходом. Я виявив, що кількість занурених місць> 0 та кількість мусудоун == підрахунок руху миші є хорошим способом виявити мишу. Я не можу дублювати це справжньою мишкою.
Пітер Вустер

36

Станом на 2018 рік існує хороший і надійний спосіб визначити, чи є у браузера миша (або подібний пристрій введення): функції взаємодії з мультимедійними засобами CSS4 які зараз підтримуються практично будь-яким сучасним браузером (крім IE 11 та спеціальних мобільних браузерів).

W3C:

Функція медіа-покажчика використовується для запиту про наявність та точність вказівного пристрою, такого як миша.

Дивіться наступні варіанти:

    /* The primary input mechanism of the device includes a 
pointing device of limited accuracy. */
    @media (pointer: coarse) { ... }

    /* The primary input mechanism of the device 
includes an accurate pointing device. */
    @media (pointer: fine) { ... }

    /* The primary input mechanism of the 
device does not include a pointing device. */
    @media (pointer: none) { ... }

    /* Primary input mechanism system can 
       hover over elements with ease */
    @media (hover: hover) { ... }

    /* Primary input mechanism cannot hover 
       at all or cannot conveniently hover 
       (e.g., many mobile devices emulate hovering
       when the user performs an inconvenient long tap), 
       or there is no primary pointing input mechanism */
    @media (hover: none) { ... }

    /* One or more available input mechanism(s) 
       can hover over elements with ease */
    @media (any-hover: hover) { ... }


    /* One or more available input mechanism(s) cannot 
       hover (or there are no pointing input mechanisms) */
    @media (any-hover: none) { ... }

Медіа-запити також можна використовувати в JS:

if(window.matchMedia("(any-hover: none)").matches) {
    // do sth
}

Пов'язані:

Документація на W3: https://www.w3.org/TR/mediaqueries-4/#mf-interaction

Підтримка браузера: https://caniuse.com/#search=media%20features

Аналогічна проблема: Визначте, чи підтримує клієнтський пристрій: наведення курсора та: фокус


Мені особисто подобається ця відповідь, але на даний момент (10/19), @media hover та покажчик CSS-запитів доступні лише на ~ 85% пристроїв у всьому світі за даними caniuse.com. Звичайно, непогано, переважніше 95% або вище. Сподіваємось, це скоро стане стандартним для пристроїв.
MQuiggGeorgia

1
@MQuiggGeorgia В основному я згоден з вашою критикою в основному, вона ще не підтримується скрізь. Досі caniuse.com для мене каже, що він підтримується 91,2% ( caniuse.com/#feat=css-media-interaction ). При ближчому розгляді його підтримують скрізь, крім IE 11 та спеціальних сплющених браузерів на мобільних пристроях. Справедливості це справедливо для будь-якої сучасної функції, оскільки Microsoft давно перестала впроваджувати функції IE. Для IE 11 ви можете скористатися відступом з інших відповідей тут.
Blackbam

23

@ Відповідь Wyatt чудова і дає нам багато про що подумати.

У моєму випадку я вирішив прослухати першу взаємодію, щоб лише потім встановити поведінку. Отже, навіть якщо у користувача є миша, я буду вважати сенсорним пристроєм, якщо перша взаємодія була дотиком.

Враховуючи заданий порядок обробки подій :

  1. сенсорний запуск
  2. сенсорний рух
  3. дотик
  4. миші
  5. миші
  6. замусоване
  7. миша
  8. клацніть

Можна припустити, що якщо подія миші спрацьовує перед дотиком, це справжня подія миші, а не емуляція. Приклад (використовуючи jQuery):

$(document).ready(function() {
    var $body = $('body');
    var detectMouse = function(e){
        if (e.type === 'mousedown') {
            alert('Mouse interaction!');
        }
        else if (e.type === 'touchstart') {
            alert('Touch interaction!');
        }
        // remove event bindings, so it only runs once
        $body.off('mousedown touchstart', detectMouse);
    }
    // attach both events to body
    $body.on('mousedown touchstart', detectMouse);
});

Це працювало для мене


Не працює для мене, Ipad Safari (IOS8.3) також виявляє мишу за допомогою цього фрагмента
netzaffin

3
@netzaffin. Дякую за відгук, я виявив, що це більш послідовно використовувати mousedown замість миші. Ви подивитеся на цю загадку з вашого IOS і повідомте мені про результат? Привітання jsfiddle.net/bkwb0qen/15/embedded/result
Hugo Silva

1
Якщо у вас є сенсорний екран з мишкою, буде виявлено лише спочатку використаний метод введення.
0xcaff

11

Виявити це можливо лише в тому випадку, якщо веб-переглядач здатний на дотик . Немає способу дізнатися, чи є насправді підключений сенсорний екран або миша.

Можна визначити пріоритет використання, хоча слухаючи сенсорну подію замість події миші, якщо виявлена ​​здатність дотику.

Щоб виявити крос-браузер з можливістю дотику:

function hasTouch() {
    return (('ontouchstart' in window) ||       // html5 browsers
            (navigator.maxTouchPoints > 0) ||   // future IE
            (navigator.msMaxTouchPoints > 0));  // current IE10
}

Тоді можна скористатися цим для перевірки:

if (!hasTouch()) alert('Sorry, need touch!);

або вибрати, яку подію слухати:

var eventName = hasTouch() ? 'touchend' : 'click';
someElement.addEventListener(eventName , handlerFunction, false);

або використовувати окремі підходи для дотику та без дотику:

if (hasTouch() === true) {
    someElement.addEventListener('touchend' , touchHandler, false);

} else {
    someElement.addEventListener('click' , mouseHandler, false);

}
function touchHandler(e) {
    /// stop event somehow
    e.stopPropagation();
    e.preventDefault();
    window.event.cancelBubble = true;
    // ...
    return false; // :-)
}
function mouseHandler(e) {
    // sorry, touch only - or - do something useful and non-restrictive for user
}

Для миші можна визначити, лише якщо миша використовується, а не вона існує чи ні. Можна встановити глобальний прапор, щоб вказати, що миша була виявлена ​​за допомогою використання (подібне до існуючої відповіді, але трохи спрощене):

var hasMouse = false;

window.onmousemove = function() {
    hasMouse = true;
}

(не можна включати mouseupабо mousedownоскільки ця подія також може бути спровокована дотиком)

Браузери обмежують доступ до системних API API низького рівня, необхідних для виявлення функцій, таких як апаратні можливості системи, в якій вона використовується.

Існує можливість, можливо, написати плагін / розширення для доступу до них, але через JavaScript і DOM таке виявлення обмежене для цієї мети, і потрібно було б написати плагін, специфічний для різних платформ ОС.

Отже, на закінчення: таке виявлення можна оцінити лише за "хорошою здогадкою".


8

Коли медіа-запити 4 рівня доступні в браузерах, ми зможемо використовувати запити "покажчик" та "наведення курсора" для виявлення пристроїв за допомогою миші.

Якщо ми дійсно хочемо передавати цю інформацію в Javascript, ми можемо використовувати CSS-запит для встановлення конкретних стилів відповідно до типу пристрою, а потім використовувати getComputedStyle в Javascript для читання цього стилю та вивести з нього вихідний тип пристрою.

Але миша може бути підключена або відключена від мережі, і користувач, можливо, захоче переключитися між дотиком і мишкою. Тому нам може знадобитися виявити цю зміну і запропонувати змінити інтерфейс або зробити це автоматично.


1
Зокрема, any-pointerіany-hover дозволить вивчити всі застосовні можливості пристрою. Приємно зазирнути, як ми можемо вирішити цю проблему в майбутньому! :)
Джордан Грей

2
window.matchMedia ("(будь-який вказівник: грубо)"). match === true?
4esn0k

7

Оскільки ви все-таки плануєте запропонувати спосіб перемикання між інтерфейсами, чи було б можливо просто попросити користувача натиснути посилання або кнопку, щоб "ввести" правильну версію програми? Тоді ви могли б згадати їх перевагу щодо майбутніх відвідувань. Це не високотехнологічний, але на 100% надійний :-)


2
Це насправді досить гарна пропозиція, але це затримує час, перш ніж користувач потрапить на реальний інтерфейс. Також мені доведеться передбачити спосіб перемикання після початкового вибору. Закінчується більша робота, ніж якби її просто можна було виявити ..
Джон Gjengset

1
Запитати користувача - це найкращий спосіб - якщо це не завжди надійно - і надає зручне місце для розміщення сповіщень про оновлення, а що ні. Я думаю, ти
передумав

4

@SamuelRossille На жаль, жодних браузерів, які я знаю, можна було б викрити існування (або її відсутність) миші.

Отже, маючи на увазі, ми просто повинні постаратися зробити все можливе в нашому існуючому варіанті ... події. Я знаю, що це не зовсім те, що ти шукаєш ... погодився, це наразі далеко не ідеально.

Ми можемо зробити все можливе, щоб з’ясувати, чи користувач користується мишею чи торканням у будь-який момент. Ось швидкий і брудний приклад використання jQuery & Knockout:

//namespace
window.ns = {};

// for starters, we'll briefly assume if touch exists, they are using it - default behavior
ns.usingTouch = ko.observable(Modernizr.touch); //using Modernizr here for brevity.  Substitute any touch detection method you desire

// now, let's sort out the mouse
ns.usingMouse = ko.computed(function () {
    //touch
    if (ns.usingTouch()) {
        //first, kill the base mousemove event
        //I really wish browsers would stop trying to handle this within touch events in the first place
        window.document.body.addEventListener('mousemove', function (e) {
            e.preventDefault();
            e.stopImmediatePropagation();
        }, true);

        //remove mouse class from body
        $('body').removeClass("mouse");

        //switch off touch listener
        $(document).off(".ns-touch");

        // switch on a mouse listener
        $(document).on('mousemove.ns-mouse', function (e) {
            if (Math.abs(window.lastX - e.clientX) > 0 || window.lastY !== e.clientY) {
                ns.usingTouch(false);  //this will trigger re-evaluation of ns.usingMouse() and result in ns.usingMouse() === true
            }
        });

        return false;
    }
    //mouse
    else {
        //add mouse class to body for styling
        $('body').addClass("mouse");

        //switch off mouse listener
        $(document).off(".ns-mouse");

        //switch on a touch listener
        $(document).on('touchstart.ns-touch', function () { ns.usingTouch(true) });

        return true;
    }
});

//tests:
//ns.usingMouse()
//$('body').hasClass('mouse');

Тепер ви можете прив’язати / підписатися на користування Mouse () та usingTouch () та / або впорядкувати свій інтерфейс з класом body.mouse . Інтерфейс буде перемикатися вперед і назад, як тільки виявиться курсор миші та на сенсорному старті.

Сподіваємось, незабаром у постачальників браузерів з’являться кращі варіанти.


2

Tera-WURFL може повідомити вам про можливості пристрою, який відвідує ваш сайт , порівнявши підпис браузера з його базою даних. Подивіться, це безкоштовно!


1
Це не працює для пристроїв, які можуть мати або не мати сенсорні екрани та мишу. Наприклад, настільний комп’ютер Windows може бути підключений до сенсорного екрану, але зазвичай також матиме мишу, тоді як планшет може також працювати під керуванням Windows, але може не мати миші.
Jon Gjengset

@Jonhoo Просто припустимо, що до операційних систем Desktop встановлена ​​миша. Зрештою, вони повинні підтримувати широкий спектр програмного забезпечення, яке не було розроблено з сенсорним екраном.
Джіджі

1
А як щодо планшетів під керуванням звичайної Windows 8? Або Linux? Або ноутбуки під управлінням Android?
Джон Gjengset

2
@Jonhoo Очевидно, що такий підхід є менш оптимальним, але немає портативного способу знати це (поки що). Якщо у вас працює ноутбук з Android, просто припускайте, що це сенсорний пристрій. Якщо у вас працює планшетний ПК Windows8, просто припустіть, що він працює з мишею (ОС повинна імітувати мишу для програм без дотику).
Джіджі

Зараз це настільки застаріло, що більше не актуально.
Інженер

2

Чому ви просто не виявите, чи має вона здатність відчувати дотики та / або реагувати на рухи миші?

// This will also return false on
// touch-enabled browsers like Chrome
function has_touch() {
  return !!('ontouchstart' in window);
}

function has_mouse() {
  return !!('onmousemove' in window);
}

4
Оскільки деякі браузери (наприклад, IE9) повідомляють, що функція існує, навіть якщо вона ніколи не буде запущена. Я вважаю, що це також "правильна" поведінка.
Джон Гженсет

чому б ви використовували функцію? просто has_touch = 'ontouchstart' in windowвистачить тощо.
vsync

Що ж, це працює принаймні на Chrome 47 для OS X. Повідомлення немає ontouchstart.
freakhead

2

Це працювало для мене в подібній ситуації. В основному, припустімо, що у користувача немає миші, поки ви не побачите коротку серію послідовних рухів миші, не втручаючись у власні міста чи мишачі. Не дуже елегантно, але це працює.

var mousedown = false;
var mousemovecount = 0;
function onMouseDown(e){
    mousemovecount = 0;
    mousedown = true;
}
function onMouseUp(e){
    mousedown = false;
    mousemovecount = 0;
}
function onMouseMove(e) {
    if(!mousedown) {
        mousemovecount++;
        if(mousemovecount > 5){
            window.removeEventListener('mousemove', onMouseMove, false);
            console.log("mouse moved");
            $('body').addClass('has-mouse');
        }
    } else {
        mousemovecount = 0;
    }
}
window.addEventListener('mousemove', onMouseMove, false);
window.addEventListener('mousedown', onMouseDown, false);
window.addEventListener('mouseup', onMouseUp, false);

0

Подивіться на modenizr, однією з його особливостей є дотик

http://modernizr.com/docs/#features-misc

Хоча я ще не протестував повністю, схоже, це працює дуже добре

Також це посилання пов'язано зі сторінки модернізації http://www.html5rocks.com/en/mobile/touchandmouse/


Це намагається виявити сенсорну здатність, а не те, чи є сенсорний ТІЛЬКИ та немає можливості миші. Це питання принципово відрізняється від сенсорного виявлення.
Jimbo Jonny

0

Як зазначали інші, остаточно виявити, чи є у них миша, ненадійне. Це можна легко змінити, залежно від пристрою. Це, безумовно, те, що ви не можете надійно зробити з булевою правдою чи помилкою, принаймні, в масштабі документа.

Події з дотиком та події миші ексклюзивні. Тож це може дещо допомогти вживати різних дій. Проблема полягає в тому, що події дотику ближче до подій миші вгору / вниз / переміщення, а також викликають подію натискання.

Після запитання ви говорите, що хочете навести курсор на попередній перегляд. Крім того, я не знаю ніяких інших особливостей вашого інтерфейсу. Я припускаю що при відсутності миші ви хочете, щоб попередній перегляд торкнувся, тоді як натискання робить іншу дію через попередній перегляд наведення курсору.

Якщо це так, ви можете скористатися ледачим підходом до виявлення:

Події onclick завжди передуватиме подію onmouseover за допомогою миші. Тож зауважте, що миша знаходиться зверху на елемент, який натиснув.

Це можна зробити за допомогою події в режимі миші, яка переноситься на весь документ. Ви можете event.targetзаписати, на якому елементі знаходиться миша. Потім всередині своїх подій onclick ви можете перевірити, чи дійсно миша над елементом, що натискається (або дочірнім елементом).

Звідти ви можете вибрати або покластись на подію натискання обох і вжити дії A або B залежно від результату. Дія B може бути нічого, якщо деякі сенсорні пристрої не випробовують події клацання (замість цього вам доведеться покладатися на події ontouch *).


0

Я не думаю, що неможливо визначити пристрій, що стосується лише дотику (наскільки мені відомо). Основна проблема полягає в тому, що всі події миші та клавіатури запускаються і сенсорними пристроями. Дивіться наступний приклад, обидва сповіщення повертаються вірно для пристроїв із сенсорним доступом.

function is_touch_present() {
  return ('ontouchstart' in window) || ('onmsgesturechange' in window);
}

function is_mouse_present() {
  return (('onmousedown' in window) && ('onmouseup' in window) && ('onmousemove' in window) && ('onclick' in window) && ('ondblclick' in window) && ('onmousemove' in window) && ('onmouseover' in window) && ('onmouseout' in window) && ('oncontextmenu' in window));
}

alert("Touch Present: " + is_touch_present());
alert("Mouse Present: " + is_mouse_present());

2
Safari ipad повертається trueза'onmousedown' in window
vsync

0

Найкраща ідея, на мою думку, - це mousemoveслухач (на даний момент найкраща відповідь). Я вважаю, що цей метод потрібно трохи підправити. Це правда, що браузери на основі дотику наслідують навіть подію переміщення миші, як ви бачите в цій дискусії про iOS , тому нам слід бути обережними.

Має сенс, що браузери на основі дотику наслідуватимуть цю подію лише тоді, коли користувач торкнеться екрана (палець користувача вниз). Це означає, що ми повинні додати тест під час роботи з обробкою миші, щоб побачити, яка кнопка миші знищена (якщо така є) під час події. Якщо жодна кнопка миші не вниз, ми можемо сміливо припустити, що справжня миша присутня. Якщо кнопка миші вниз, тест залишається непереконливим.

То як би це було здійснено? Це питання показує, що найнадійнішим методом дослідження того, яка кнопка миші опускається під час руху миші, є насправді прослуховування трьох подій на рівні документа: переміщення миші, миша та миша. Вгору та вниз встановлюватиметься лише глобальний буловий прапор. Хід виконає тест. Якщо у вас є хід і булева помилка, ми можемо припустити, що миша присутня. Дивіться запитання для точних прикладів коду.

Остаточний коментар. Цей тест не є ідеальним, оскільки його неможливо виконати у завантажувальний час. Тому я б застосував метод прогресивного вдосконалення, як було запропоновано раніше. За замовчуванням покажіть версію, яка не підтримує специфічний для миші інтерфейс наведення миші. Якщо миша виявлена, увімкніть цей режим під час виконання за допомогою JS. Це повинно виглядати максимально безшовно для користувача.

Для підтримки змін у конфігурації користувача (тобто миша відключена), ви можете періодично проводити повторну перевірку. Хоча я вважаю, що в цьому випадку буде краще просто повідомити користувача про два режими і дозволити користувачам вручну перемикатися між ними (як на вибір мобільного / робочого столу, який завжди можна змінити).


Дякую за хороші рішення щодо подолання ... Я думаю, що головна проблема, що не вирішується, мені доведеться вдатися до однієї з них
Самюель Россіль

На жаль, рух миші спрацьовує при натисканні на ipad. Тестується лише на тренажері. Для hasMouse () я використовував if (! ('Ontouchstart' у вікні)) return true; але не працює на підтримуваних сенсорним ноутбуках.
Кріс Гунавардена

@Chris G - iPad hell ... (стукав головою об стіну)
vsync

0

Провів кілька тестів на різних комп'ютерах, Linux, iPhone, Android телефонах і вкладках. Дивно, що не існує простого кулезахисного рішення. Проблема виникає, коли деякі, у яких Touch та ні миша, ще не подають події Touch and Mouse додатку. Оскільки ви хочете підтримувати екземпляри, що стосуються лише миші та лише дотику, хочете обробити обидва, але це спричиняє подвійні випадки взаємодії користувачів. Якщо може знати, що миша не присутня на пристрої, то може знати, щоб ігнорувати підроблені / вставлені події миші. Спробуйте встановити прапор, якщо MouseMove зустрічається, але деякі браузери кидають підроблені MouseMove, а також MouseUp та MouseDown. Спробував вивчити часові позначки, але подумав, що це занадто ризиковано. Підсумок: я знайшов браузери, які створювали підроблені події миші, завжди вставляли єдину MouseMove безпосередньо перед вставленою MouseDown. У 99,99% моїх випадків, при запуску в системі, яка має справжню мишу, є кілька послідовних подій MouseMove - як мінімум два. Отже, слідкуйте за тим, чи зустрічається система двома послідовними подіями MouseMove і заявляйте, що немає миші, якщо ця умова ніколи не виконується. Це, мабуть, занадто просто, але він працює на всіх моїх тестових установках. Думаю, я буду дотримуватися цього, поки не знайду кращого рішення. - Джим W


0

Просте рішення в jQuery для виявлення використання миші, яке вирішує проблему, коли мобільні пристрої також викликають подію "mousemove". Просто додайте слухача сенсорного запуску, щоб видалити слухача руху миші, щоб він не спрацьовував на дотик.

$('body').one('touchstart.test', function(e) {
  // Remove the mousemove listener for touch devices
  $('body').off('mousemove.test');
}).one('mousemove.test', function(e) {
  // MOUSE!
});

Звичайно, пристрій все-таки може бути сенсорним І мишею, але вищесказане гарантує, що справжня миша була використана.


0

Щойно знайшлося рішення, яке я вважаю досить елегантним.

// flag as mouse interaction by default
var isMouse = true;

// detect a touch event start and flag it
$(window).on('touchstart', function () {
  // if triggers touchstart, toggle flag
  // since touch events come before mouse event / click
  // callback of mouse event will get in callback
  // `isMouse === false`
  isMouse = false;
});

// now the code that you want to write
// should also work with `mouse*` events
$('a.someClass').on('click', function () {
  if (isMouse) {
    // interaction with mouse event
    // ...
  } else {
    // reset for the next event detection
    // this is crucial for devices that have both
    // touch screen and mouse
    isMouse = true;

    // interaction with touch event
    // ...
  }
});

0

Я зіткнувся з тією ж проблемою, де один дотик також був зареєстрований як клік. Після того, як я прочитав коментарі топ-проголосованих відповідей, я придумав власне рішення:

var body = document.getElementsByTagName('body')[0];
var mouseCount = 0;

// start in an undefined state 
// (i use this to blend in elements once we decide what input is used)
var interactionMode = 'undefined';


var registerMouse = function() {
  // count up mouseCount every time, the mousemove event is triggered
  mouseCount++;

  // but dont set it instantly. 
  // instead wait 20 miliseconds (seems to be a good value for multiple move actions), 
  // if another mousemove event accoures switch to mouse as interaction 
  setTimeout(function() {
    // a touch event triggers also exactly 1 mouse move event.
    // So only if mouseCount is higher than 1 we are really moving the cursor by mouse.
    if (mouseCount > 1) {
      body.removeEventListener('mousemove', registerMouse);
      body.removeEventListener('touchend', registerTouch);

      interactionMode = 'mouse';
      console.log('now mousing');
      listenTouch();
    }

    // set the counter to zero again
    mouseCount = 0;
  }, 20);
};

var registerTouch = function() {
  body.removeEventListener('mousemove', registerMouse);
  body.removeEventListener('touchend', registerTouch);

  interactionMode = 'touch';
  console.log('now touching');
  mouseCount = 0;

  listenMouse();
};

var listenMouse = function() {
  body.addEventListener("mousemove", registerMouse);
};
var listenTouch = function() {
  body.addEventListener("touchend", registerTouch);
};

listenMouse();
listenTouch();

// after one second without input, assume, that we are touching
// could be adjusted to several seconds or deleted
// without this, the interactionMode would stay 'undefined' until first mouse or touch event
setTimeout(function() {
  if (!body.classList.contains('mousing') || body.classList.contains('touching')) {
    registerTouch();
  }
}, 1000);
/* fix, so that scrolling is possible */

html,
body {
  height: 110%;
}
Mouse or touch me

Єдина проблема, яку я знайшов, - це те, що ви повинні мати можливість прокрутки, щоб правильно виявити сенсорну подію. одна вкладка (дотик) може створити проблеми.


0

Я витратив години, розгадуючи цю проблему для свого додатка Phonegap, і я придумав цей злом. Він генерує попередження консолі, якщо викликана подія є "пасивною" подією, це означає, що вона не приводить жодних змін, але вона працює! Мені були б цікаві будь-які ідеї щодо вдосконалення чи кращого методу. Але це ефективно дозволяє моєму $ .touch () використовувати універсально.

$(document).ready(function(){
  $("#aButton").touch(function(origElement, origEvent){
    console.log('Original target ID: ' + $(origEvent.target).attr('id'));
  });
});

$.fn.touch = function (callback) {
    var touch = false;
    $(this).on("click", function(e){
        if (!touch)
        {
            console.log("I click!");
            let callbackReal = callback.bind(this);
            callbackReal(this, e);
        }else{
            touch = true;
        }
        touch = false;
    });
    $(this).on("touchstart", function(e){
        if (typeof e.touches != typeof undefined)
        {
            e.preventDefault();
            touch = true;
            console.log("I touch!");
            let callbackReal = callback.bind(this);
            callbackReal(this, e);
        }
    });
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<button id="aButton">A Button</button>


0

Основна проблема, яку я бачу тут, полягає в тому, що більшість сенсорних пристроїв запускають події миші разом із відповідним сенсорним (touchstart -> mousedown, touchmove -> mousemove тощо). Тільки для клавіатур, нарешті, для сучасних вони мають загальний браузер, тому ви навіть не можете виявити наявність класу MouseEvent.

Менш болісним рішенням, на мою думку, було б відображення меню при запуску (з керуванням «alt» для користувачів клавіатури лише) і, можливо, зберігання вибору з localStorage / cookies / сервером або іншим, щоб зберегти той самий вибір наступним час, коли відвідувач приходить.


-4

Я настійно рекомендую проти такого підходу. Розгляньте сенсорний екран, пристрої розміру настільних ПК, і вам доведеться вирішити інший набір проблем.

Будь ласка, зробіть вашу програму доступною без миші (тобто без попереднього попереднього перегляду).


1
Це саме те, що я намагаюся зробити. Я намагаюся створити інтерфейс, який буде працювати найкращим чином як на планшетах (без миші), так і на миші, але ці інтерфейси обов'язково дуже різні.
Джон Gjengset

Я погоджуюсь з бурхливим. Найкраще використовувати детекцію пристрою (наприклад, DeviceAtlas) та вибрати запропонований інтерфейс під час завантаження.
Teemu Ikonen

-4

Хочу порекомендувати сценарій, який мені допоміг:

Я прочитав і спробував усе запропоноване, без достатніх результатів.

Потім я дослідив ще кілька і знайшов цей код - device.js

Я використовую це на веб-сайті свого клієнта, щоб виявити існування миші:
( <html>повинен мати desktopклас), і це здається досить непоганим, а для touchпідтримки я просто регулярно перевіряю 'ontouchend' in documentі використовую інформацію з обох детективів, щоб припустити конкретну річ, яка мені потрібна.


Це рівнозначно нюханню UA, яке вже багато разів піднімалося в цій темі. Це не вирішує випадку пристроїв із мишею AND touch, як Windows 8, і це, безумовно, не підтверджує майбутнє.
Гюго Сільва

Я використовую його для вирішення цього ТОЧНОГО випадку, який ви згадали у заяві клієнта, і він працює добре. це майбутнє доказ, оскільки його підтримує розробник.
vsync

2
Випадок, про який я згадав (ноутбук із включеним дотиком), буде визначений вашим сценарієм як «Настільний», хоча я не можу використовувати мишу. "це доказ у майбутньому, оскільки його підтримує розробник", - я думаю, ви повністю пропустили пункт "майбутнього доказування" тут. І якби ви прочитали і спробували все, як ви заявили, ви помітили б, що відповідь Джіджі вже говорить про нюхання UA.
Гюго Сільва

-7

Як правило, краща ідея виявити, чи підтримується функція миші, а не тип ОС / браузера. Ви можете зробити це просто за допомогою наступного:

if (element.mouseover) {
    //Supports the mouseover event
}

Будьте впевнені, що ви не зробите наступне:

if (element.mouseover()) {
    // Supports the mouseover event
}

Останній насправді називав би метод, а не перевіряв його існування.

Докладніше можна прочитати тут: http://www.quirksmode.org/js/support.html


2
Я дійсно не знаю, що отримати від вашої посади, але якщо ('onmouseover' у $ ('body') [0]) попередження ('onmouseover'); відображає повідомлення і в iPhone
nraynaud

1
Це лише перевіряє, чи визначена функція миші, яка була б майже у всіх браузерах. Він не визначає, чи дійсно присутня миша.
Джон Gjengset
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.