Mendeteksi bahwa browser tidak memiliki mouse dan hanya sentuh

149

Saya sedang mengembangkan aplikasi web (bukan situs web dengan halaman teks yang menarik) dengan antarmuka yang sangat berbeda untuk disentuh (jari Anda menyembunyikan layar saat Anda mengklik) dan mouse (sangat bergantung pada pratinjau kursor). Bagaimana saya bisa mendeteksi bahwa pengguna saya tidak memiliki mouse untuk menyajikan antarmuka yang tepat kepadanya? Saya berencana untuk meninggalkan saklar untuk orang-orang dengan mouse dan sentuhan (seperti beberapa notebook).

Kemampuan acara sentuh di browser sebenarnya tidak berarti pengguna menggunakan perangkat sentuh (misalnya, Modernizr tidak memotongnya). Kode yang menjawab pertanyaan dengan benar harus kembali salah jika perangkat memiliki mouse, benar sebaliknya. Untuk perangkat dengan mouse dan sentuhan, itu harus mengembalikan false (tidak hanya menyentuh)

Sebagai catatan, antarmuka sentuh saya mungkin juga cocok untuk perangkat yang hanya menggunakan keyboard, jadi lebih kekurangan mouse yang ingin saya deteksi.

Agar lebih jelas, berikut adalah API yang ingin saya terapkan:

// 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);
nraynaud
sumber
Saya pikir Anda perlu memikirkan kembali desain Anda jika Anda ingin satu aplikasi berlaku untuk desktop dan mobile / touch tetapi memiliki perilaku yang berbeda untuk masing-masing. Saya tidak berpikir apa yang Anda cari sebenarnya mungkin pada saat ini, karena pencarian cepat di Google untuk "javascript mendeteksi mouse" menunjukkan satu posting yang cukup berguna di quirksmode.org untuk mendeteksi berbagai keadaan mouse (klik, posisi, dll), tetapi NOL menghasilkan apakah mouse benar-benar ada atau tidak.
davethegr8
24
Mungkin itu karena Google tidak membantu yang saya tanyakan di sini.
nraynaud
2
Sudahkah Anda mencoba mendokumentasikan mouseenter dari jquery? $ (dokumen) .mouseenter (fungsi (e) {alert ("mouse");});
Parag Gajjar
4
Setelah mempertimbangkan hampir selusin jalan yang menjanjikan hanya untuk menolak masing-masing dalam beberapa menit, pertanyaan ini membuat saya sangat gila.
Jordan Grey

Jawaban:

65

Masalah utama adalah bahwa Anda memiliki kelas berbeda dari perangkat / kasus penggunaan:

  1. Mouse dan keyboad (desktop)
  2. Hanya menyentuh (ponsel / tablet)
  3. Mouse, keyboard, dan sentuhan (sentuh laptop)
  4. Sentuh dan keyboard (keyboard bluetooth pada tablet)
  5. Hanya mouse (Pengguna yang dinonaktifkan / preferensi penelusuran)
  6. Hanya keyboard (Pengguna yang dinonaktifkan / preferensi penelusuran)
  7. Sentuh dan tetikus (mis., Arahkan acara dari pena Galaxy Note 2)

Yang lebih buruk, adalah bahwa seseorang dapat bertransisi dari beberapa kelas ini ke kelas lain (colok mouse, menyambungkan ke keyboard), atau pengguna mungkin TAMPAK berada di laptop biasa sampai mereka menjangkau dan menyentuh layar.

Anda benar dalam menganggap bahwa kehadiran konstruktor acara di browser bukanlah cara yang baik untuk bergerak maju (dan itu agak tidak konsisten). Selain itu, kecuali jika Anda melacak peristiwa yang sangat spesifik atau hanya mencoba untuk mengesampingkan beberapa kelas di atas, menggunakan acara itu sendiri bukanlah bukti penuh.

Misalnya, Anda telah menemukan bahwa pengguna telah mengeluarkan mouse nyata (bukan yang palsu dari acara sentuh, lihat http://www.html5rocks.com/en/mobile/touchandmouse/ ).

Lalu apa?

Anda mengaktifkan gaya melayang? Anda menambahkan lebih banyak tombol?

Apa pun cara Anda meningkatkan waktu untuk kaca karena Anda harus menunggu acara untuk menembak.

Tetapi kemudian apa yang terjadi ketika pengguna mulia Anda memutuskan ingin mencabut mouse-nya dan melakukan sentuhan penuh .. apakah Anda menunggu dia menyentuh antarmuka Anda yang sekarang penuh sesak, lalu mengubahnya tepat setelah dia berupaya untuk menunjukkan UI Anda yang sekarang penuh sesak?

Dalam bentuk bullet, mengutip stucox di https://github.com/Modernizr/Modernizr/issues/869#issuecomment-15264101

  • Kami ingin mendeteksi keberadaan mouse
  • Ae mungkin tidak dapat mendeteksi sebelum suatu peristiwa dipecat
  • Dengan demikian, yang kami deteksi adalah jika mouse telah digunakan dalam sesi ini - tidak akan langsung dari pemuatan halaman
  • Kami mungkin juga tidak dapat mendeteksi bahwa tidak ada mouse - itu tidak akan ditentukan hingga benar (saya pikir ini lebih masuk akal daripada menetapkannya salah sampai terbukti)
  • Dan kami mungkin tidak dapat mendeteksi jika mouse terputus di tengah sesi - yang tidak dapat dibedakan dari pengguna yang menyerah dengan mouse mereka

Selain itu: browser TIDAK tahu kapan pengguna menghubungkan mouse / terhubung ke keyboard, tetapi tidak mengeksposnya ke JavaScript .. sial!

Ini akan mengarahkan Anda ke yang berikut:

Melacak kemampuan saat ini dari pengguna yang diberikan adalah kompleks, tidak dapat diandalkan, dan patut diragukan

Namun, gagasan peningkatan progresif cukup baik diterapkan di sini. Bangun pengalaman yang bekerja dengan lancar tidak peduli konteks pengguna. Kemudian buat asumsi berdasarkan fitur peramban / kueri media untuk menambahkan fungsionalitas yang relatif dalam konteks yang diasumsikan. Kehadiran mouse hanyalah salah satu dari banyak cara di mana pengguna yang berbeda pada perangkat yang berbeda mengalami situs web Anda. Buat sesuatu dengan pantas di kernelnya dan jangan terlalu khawatir tentang bagaimana orang mengklik tombol.

Wyatt
sumber
3
jawaban yang bagus Semoga pengguna selalu memiliki layar! Saya pikir masuk akal untuk membangun antarmuka di mana itu hanya untuk mode interaksi saat ini dari pengguna. Pada laptop sentuh, masuk akal untuk menyesuaikan aplikasi (yaitu :hoverelemen dan hal-hal seperti itu) ketika pengguna beralih dari mouse ke sentuhan. Tampaknya tidak mungkin bahwa pengguna saat ini menggunakan mouse + touch pada waktu yang sama (maksud saya comoonn itu seperti memiliki 2 mouse yang terhubung ke komputer yang sama hahaha)
Sebastien Lorber
@SebastienLorber - benci untuk membocorkannya kepada Anda tetapi pengguna tidak selalu memiliki layar. ( Apakah mungkin menggunakan javascript untuk mendeteksi apakah pembaca layar berjalan pada mesin pengguna? )
ashleedawg
57

Bagaimana kalau mendengarkan acara ibu jari di dokumen. Kemudian sampai Anda mendengar peristiwa itu, Anda menganggap bahwa perangkat itu hanya menyentuh atau keyboard.

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

(Di mana listendan unlistenmendelegasikan ke addEventListeneratau yang attachEventsesuai.)

Mudah-mudahan ini tidak akan menyebabkan jank visual terlalu banyak, itu akan menyedot jika Anda membutuhkan tata letak ulang besar-besaran berdasarkan mode ...

Dan
sumber
2
Ini adalah ide yang bagus, tetapi sayangnya keterlambatan dalam respon akan membuatnya tidak dapat digunakan ketika UI aplikasi tergantung pada apakah mouse tersedia. mouse bergerak di atas iframe itu sendiri ..
Jon Gjengset
7
Ini bisa berfungsi jika aplikasi dimulai dengan layar splash dan tombol "lanjutkan". Jika mouse bergerak sebelum acara mousedown pertama maka Anda memiliki mouse. Itu hanya akan gagal jika tombol dimuat langsung di bawah mouse dan pengguna memiliki tangan yang sangat mantap (bahkan memindahkan 1 piksel harus diambil).
SpliFF
49
ide yang bagus, tetapi tampaknya tidak berfungsi dalam pengujian kami . iPad memicu acara ini.
Jeff Atwood
3
@ JeffeTwood apa yang akhirnya Anda lakukan dalam kasus Anda?
Michael Haren
2
iPad pasti memicu acara mousemove, tepat sebelum acara mousedown. Saya telah menemukan bahwa mousedown count> 0 dan mousedown count == mousemove count menjadi cara yang baik untuk mendeteksi tidak ada mouse. Saya tidak bisa menduplikasi ini dengan mouse sungguhan.
Peter Wooster
36

Pada 2018 ada cara yang baik dan dapat diandalkan untuk mendeteksi apakah browser memiliki mouse (atau perangkat input serupa): fitur interaksi media CSS4 yang sekarang didukung oleh hampir semua browser modern (kecuali IE 11 dan browser ponsel khusus).

W3C:

Fitur media penunjuk digunakan untuk menanyakan keberadaan dan keakuratan perangkat penunjuk seperti mouse.

Lihat opsi berikut:

    /* 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) { ... }

Kueri media juga bisa digunakan di JS:

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

Terkait:

Dokumentasi W3: https://www.w3.org/TR/mediaqueries-4/#mf-interaction

Dukungan browser: https://caniuse.com/#search=media%20features

Masalah serupa: Mendeteksi jika perangkat klien mendukung: hover dan: status fokus

Blackbam
sumber
Saya pribadi suka jawaban ini tetapi mulai sekarang (19/10), @media hover dan pointer pertanyaan CSS hanya tersedia di ~ 85% perangkat di seluruh dunia menurut caniuse.com. Tentu tidak buruk, lebih dari 95% lebih disukai. Semoga ini akan menjadi standar pada perangkat segera.
MQuiggGeorgia
1
@MQuiggGeorgia Pada dasarnya saya setuju dengan kritik Anda pada dasarnya, itu belum didukung di mana-mana. Masih caniuse.com bagi saya mengatakan itu didukung 91,2% ( caniuse.com/#feat=css-media-interaction ). Memiliki tampilan yang lebih dekat didukung di mana-mana kecuali untuk IE 11 dan browser khusus di ponsel. Agar adil ini berlaku untuk semua fitur modern, karena Microsoft berhenti menerapkan fitur IE sejak lama. Untuk IE 11 Anda dapat menggunakan fallback dari jawaban lain di sini.
Blackbam
23

@ Wyatt jawabannya bagus dan memberi kami banyak hal untuk dipikirkan.

Dalam kasus saya, saya memilih untuk mendengarkan interaksi pertama, hanya kemudian menetapkan perilaku. Jadi, bahkan jika pengguna memiliki mouse, saya akan memperlakukan sebagai perangkat sentuh jika interaksi pertama adalah sentuhan.

Mempertimbangkan urutan yang diberikan di mana acara diproses :

  1. touchstart
  2. sentuh
  3. touchend
  4. mouseover
  5. mousemove
  6. mousedown
  7. mouseup
  8. klik

Kita dapat berasumsi bahwa jika acara mouse dipicu sebelum disentuh, ini adalah peristiwa mouse sungguhan, bukan yang ditiru. Contoh (menggunakan 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);
});

Itu berhasil bagi saya

Hugo Silva
sumber
Tidak berfungsi untuk saya, Ipad Safari (IOS8.3) juga mendeteksi mouse dengan cuplikan ini
netzaffin
3
@netzaffin. Terima kasih atas umpan baliknya, saya merasa lebih konsisten menggunakan mousedown daripada mouseover. Apakah Anda melihat biola ini dari iOS Anda dan beri tahu saya hasilnya? Cheers jsfiddle.net/bkwb0qen/15/embedded/result
Hugo Silva
1
Jika Anda memiliki layar sentuh dengan mouse, hanya metode input yang digunakan terlebih dahulu yang akan terdeteksi.
0xcaff
11

Ini hanya mungkin untuk mendeteksi jika browser mampu menyentuh . Tidak ada cara untuk mengetahui apakah itu benar-benar memiliki layar sentuh atau mouse yang terhubung.

Orang dapat memprioritaskan penggunaannya dengan mendengarkan acara sentuh alih-alih acara mouse jika kemampuan sentuh terdeteksi.

Untuk mendeteksi kemampuan lintas-browser:

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

Maka orang dapat menggunakan ini untuk memeriksa:

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

atau untuk memilih acara mana yang ingin didengarkan, baik:

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

atau gunakan pendekatan terpisah untuk sentuhan vs non-sentuhan:

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
}

Untuk mouse, seseorang hanya dapat mendeteksi jika mouse sedang digunakan, tidak apakah itu ada atau tidak. Seseorang dapat mengatur bendera global untuk menunjukkan bahwa mouse terdeteksi oleh penggunaan (mirip dengan jawaban yang ada, tetapi sedikit disederhanakan):

var hasMouse = false;

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

(orang tidak dapat memasukkan mouseupatau mousedownkarena acara ini juga dapat dipicu oleh sentuhan)

Browser membatasi akses ke API sistem tingkat rendah yang diperlukan untuk dapat mendeteksi fitur-fitur seperti kemampuan perangkat keras dari sistem yang digunakan.

Ada kemungkinan untuk mungkin menulis plugin / ekstensi untuk mengaksesnya tetapi melalui JavaScript dan DOM deteksi semacam itu terbatas untuk tujuan ini dan orang harus menulis sebuah plugin khusus untuk berbagai platform OS.

Jadi kesimpulannya: deteksi seperti itu hanya dapat diperkirakan dengan "tebakan yang baik".


sumber
8

Ketika Media Query Level 4 tersedia di browser, kita akan dapat menggunakan kueri "pointer" dan "hover" untuk mendeteksi perangkat dengan mouse.

Jika kami benar-benar ingin mengomunikasikan informasi itu ke Javascript, kami dapat menggunakan kueri CSS untuk mengatur gaya tertentu sesuai dengan jenis perangkat, dan kemudian menggunakan getComputedStyledalam Javascript untuk membaca gaya itu, dan menurunkan jenis perangkat asli darinya.

Tetapi mouse dapat dihubungkan atau dicabut kapan saja, dan pengguna mungkin ingin beralih antara sentuhan dan mouse. Jadi kita mungkin perlu mendeteksi perubahan ini, dan menawarkan untuk mengubah antarmuka atau melakukannya secara otomatis.

joeytwiddle
sumber
1
Secara khusus, any-pointerdanany-hover akan membiarkan Anda menyelidiki semua kemampuan perangkat yang berlaku. Senang bisa mengintip bagaimana kita bisa memecahkan masalah ini di masa depan! :)
Jordan Gray
2
window.matchMedia ("(any-pointer: coarse)"). Kecocokan === true?
4esn0k
7

Karena Anda berencana menawarkan cara untuk beralih antar antarmuka, apakah mungkin meminta pengguna untuk mengklik tautan atau tombol untuk "memasukkan" versi aplikasi yang benar? Kemudian Anda dapat mengingat preferensi mereka untuk kunjungan di masa mendatang. Ini bukan teknologi tinggi, tetapi 100% dapat diandalkan :-)

Brandan
sumber
2
Ini sebenarnya saran yang cukup bagus, tetapi menunda waktu sebelum pengguna sampai ke antarmuka nyata. Juga, saya harus menyediakan cara untuk beralih setelah pilihan awal. Berakhir menjadi lebih banyak pekerjaan daripada jika hanya bisa dideteksi ..
Jon Gjengset
1
Meminta pengguna jelas merupakan cara terbaik - jika tidak selalu mudah - Dan memberi Anda tempat yang nyaman untuk memasang notifikasi peningkatan dan apa yang tidak. Saya pikir Anda terlalu memikirkan "masalah" ..
T4NK3R
4

@SamuelRossille Tidak ada peramban yang saya sadari mengekspos keberadaan (atau ketiadaan) mouse, sayangnya.

Jadi, dengan itu dikatakan, kita hanya harus mencoba dan melakukan yang terbaik yang kita bisa dengan pilihan kita yang ada ... acara. Saya tahu itu bukan apa yang Anda cari ... setuju itu saat ini jauh dari ideal.

Kita dapat melakukan yang terbaik untuk mengetahui apakah pengguna menggunakan mouse atau sentuhan pada saat tertentu. Berikut ini adalah contoh cepat dan kotor menggunakan 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');

Sekarang Anda dapat mengikat / berlangganan menggunakanMouse () & usingTouch () dan / atau gaya antarmuka Anda dengan kelas body.mouse . Antarmuka akan beralih bolak-balik segera setelah kursor mouse terdeteksi dan di layar sentuh.

Mudah-mudahan kita akan memiliki beberapa opsi yang lebih baik dari vendor browser segera.

daredev
sumber
2

Tera-WURFL dapat memberi tahu Anda kemampuan perangkat yang mengunjungi situs Anda dengan membandingkan tanda tangan browser dengan basis datanya. Coba lihat, gratis!

Gigi
sumber
1
Ini tidak akan berfungsi untuk perangkat yang mungkin memiliki layar sentuh dan mouse. Misalnya, komputer desktop Windows mungkin terhubung ke layar sentuh, tetapi biasanya juga memiliki mouse, sedangkan tablet mungkin juga menjalankan Windows, tetapi mungkin tidak memiliki mouse yang terhubung ..
Jon Gjengset
@ Jonhoo Anggap saja sistem operasi Desktop memiliki mouse yang terpasang. Lagi pula, mereka harus mendukung berbagai perangkat lunak yang tidak dikembangkan dengan mempertimbangkan layar sentuh.
Gigi
1
Bagaimana dengan tablet yang menjalankan Windows 8 biasa? Atau Linux? Atau laptop yang menjalankan Android?
Jon Gjengset
2
@ Jonhoo Jelas pendekatan ini kurang optimal, tetapi tidak ada cara portabel untuk mengetahui hal itu (belum). Jika seseorang menjalankan laptop dengan Android, anggap saja ia mampu sentuh. Jika seseorang menjalankan tablet Windows8, anggap saja ia mampu menggunakan mouse (OS harus meniru mouse untuk program non-sentuh).
Gigi
Ini sekarang sudah usang sehingga tidak relevan lagi.
Insinyur
2

Mengapa Anda tidak mendeteksi jika memiliki kemampuan untuk merasakan sentuhan dan / atau bereaksi terhadap gerakan mouse?

// 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);
}
iblue
sumber
4
Karena beberapa browser (misalnya IE9) melaporkan bahwa fungsi tersebut ada meskipun tidak akan pernah terpicu. Saya percaya ini juga perilaku yang "benar".
Jon Gjengset
mengapa Anda menggunakan suatu fungsi? hanya has_touch = 'ontouchstart' in windowakan cukup, dan sebagainya.
vsync
Ya, itu berfungsi di Chrome 47 untuk OS X, setidaknya. Melaporkan no ontouchstart.
phreakhead
2

Ini bekerja untuk saya dalam situasi yang sama. Pada dasarnya, anggap pengguna tidak memiliki mouse sampai Anda melihat serangkaian singkat mousemoves berturut-turut, tanpa campur tangan mousedowns atau mouseups. Tidak terlalu elegan, tetapi berhasil.

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);
Michael Condouris
sumber
0

Lihat di modenizr salah satu fiturnya adalah touch

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

Meskipun saya belum diuji sepenuhnya sepertinya berfungsi dengan sangat baik

Juga ini ditautkan dari halaman modernizr http://www.html5rocks.com/en/mobile/touchandmouse/

exussum
sumber
Upaya ini untuk mendeteksi kemampuan sentuh, bukan apakah ada HANYA sentuh dan tidak ada kemampuan mouse. Pertanyaan ini pada dasarnya berbeda dari deteksi sentuhan.
Jimbo Jonny
0

Seperti yang telah ditunjukkan oleh orang lain, secara definitif mendeteksi apakah mereka memiliki mouse atau tidak dapat diandalkan. Ini dapat dengan mudah berubah, tergantung pada perangkat. Ini jelas sesuatu yang tidak dapat Anda lakukan dengan andal dengan boolean benar atau salah, setidaknya pada skala dokumen.

Acara sentuh dan acara mouse adalah eksklusif. Jadi ini dapat sedikit membantu dalam mengambil tindakan yang berbeda. Masalahnya adalah acara sentuh lebih dekat dengan mouse atas / bawah / memindahkan acara, dan juga memicu acara klik.

Dari pertanyaan Anda, Anda mengatakan ingin memiliki pratinjau melayang. Selain itu, saya tidak tahu secara spesifik tentang antarmuka Anda. Saya berasumsi bahwa dengan kekurangan mouse Anda ingin mengetuk pratinjau, sementara klik melakukan tindakan yang berbeda karena pratinjau hover.

Jika itu masalahnya, Anda bisa menggunakan pendekatan yang agak malas untuk deteksi:

Acara onclick akan selalu didahului oleh acara onmouseover dengan mouse. Jadi catat bahwa mouse ada di atas elemen yang telah diklik.

Anda bisa melakukan ini dengan acara onmousemove seluruh dokumen. Anda dapat menggunakan event.targetuntuk merekam elemen tempat mouse berada. Kemudian di dalam acara onclick Anda, Anda dapat memeriksa untuk melihat apakah mouse benar-benar di atas elemen yang diklik (atau anak elemen).

Dari sana Anda dapat memilih untuk mengandalkan acara klik untuk keduanya dan mengambil tindakan A atau B tergantung pada hasilnya. Tindakan B bisa berupa apa-apa jika beberapa perangkat sentuh tidak memancarkan acara klik (sebagai gantinya Anda harus mengandalkan acara * ontouch).

Luke
sumber
0

Saya tidak berpikir itu mungkin untuk mengidentifikasi perangkat sentuh saja (setahu saya tentu saja). Masalah utama adalah semua acara mouse dan keyboard dipecat oleh perangkat sentuh juga. Lihat contoh berikut, kedua peringatan mengembalikan true untuk perangkat sentuh.

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());
Bikas
sumber
2
Safari ipad kembali trueuntuk'onmousedown' in window
vsync
0

Ide terbaik menurut saya adalah mousemovependengar (saat ini adalah jawaban teratas). Saya percaya bahwa metode ini perlu sedikit di-tweak. Memang benar bahwa browser berbasis sentuhan meniru bahkan mousemove event, seperti yang Anda lihat dalam diskusi iOS ini , jadi kita harus sedikit berhati-hati.

Masuk akal bahwa browser berbasis sentuhan hanya akan meniru acara ini ketika pengguna mengetuk layar (jari pengguna turun). Ini berarti kita harus menambahkan tes selama pengendali mouse kita untuk melihat tombol mouse mana yang turun (jika ada) selama acara berlangsung. Jika tidak ada tombol mouse yang mati, kami dapat dengan aman menganggap mouse asli hadir. Jika tombol mouse mati, tes tetap tidak meyakinkan.

Jadi bagaimana ini diterapkan? Pertanyaan ini menunjukkan bahwa metode yang paling dapat diandalkan untuk memeriksa tombol mouse mana yang mati selama perpindahan mouse adalah dengan benar-benar mendengarkan 3 peristiwa di tingkat dokumen: mouse mouse, mouse mouse dan mouseup. Atas dan ke bawah hanya akan menetapkan bendera boolean global. Langkah tersebut akan melakukan tes. Jika Anda memiliki gerakan dan boolean salah, kita dapat mengasumsikan mouse ada. Lihat pertanyaan untuk contoh kode yang tepat.

Satu komentar terakhir .. Tes ini tidak ideal karena tidak dapat dilakukan dalam waktu buka. Oleh karena itu, saya akan menggunakan metode peningkatan progresif seperti yang disarankan sebelumnya. Secara default, tunjukkan versi yang tidak mendukung antarmuka mouse spesifik mouse. Jika mouse ditemukan, aktifkan mode ini dalam runtime menggunakan JS. Ini akan muncul semulus mungkin bagi pengguna.

Untuk mendukung perubahan dalam konfigurasi pengguna (mis. Mouse telah diputuskan), Anda dapat menguji ulang secara berkala. Meskipun saya percaya akan lebih baik dalam hal ini untuk hanya memberi tahu pengguna tentang 2 mode dan membiarkan pengguna secara manual beralih di antara mereka (sangat mirip dengan pilihan mobile / desktop yang selalu dapat dibalik).

Talkol
sumber
Terima kasih atas saran pemecahan masalah yang baik ... Saya pikir masalah utama tidak disiram saya harus menggunakan salah satu dari ini
Samuel Rossille
Sayangnya, mouse harus dipicu saat klik pada iPad. Hanya diuji dengan simulator. Untuk hasMouse () saya menggunakan if (! ('Ontouchstart' di jendela)) mengembalikan true; tetapi tidak berfungsi untuk laptop yang didukung sentuhan.
Chris Gunawardena
@ Chris G - Neraka iPad ... (membenturkan kepalaku ke dinding)
vsync
0

Menjalankan beberapa tes di berbagai PC, Linux, iPhone, ponsel Android dan tab. Aneh bahwa tidak ada solusi anti peluru yang mudah. Masalah muncul ketika beberapa yang memiliki Sentuh dan tidak ada mouse masih menyajikan acara Sentuh dan Mouse untuk aplikasi. Karena ingin mendukung instance hanya mouse dan sentuh saja, ingin memproses keduanya, tetapi ini menyebabkan dua kali lipat interaksi pengguna. Jika bisa tahu mouse tidak ada di perangkat, maka bisa tahu untuk mengabaikan acara mouse palsu / dimasukkan. Mencoba mengatur flag jika MouseMove ditemukan, tetapi beberapa browser melempar MouseMove palsu serta MouseUp dan MouseDown. Sudah mencoba memeriksa stempel waktu tetapi menganggap ini terlalu berisiko. Intinya: Saya menemukan browser yang menciptakan acara mouse palsu selalu menyisipkan MouseMove tunggal sebelum MouseDown yang dimasukkan. Dalam 99,99% dari kasus saya, saat berjalan pada sistem yang memiliki mouse asli, ada beberapa kejadian MouseMove berturut-turut - setidaknya dua. Jadi, pantau apakah sistem menemukan dua peristiwa MouseMove berturut-turut dan menyatakan tidak ada mouse jika kondisi ini tidak pernah dipenuhi. Ini mungkin terlalu sederhana, tetapi bekerja pada semua pengaturan pengujian saya. Saya pikir saya akan tetap menggunakannya sampai saya menemukan solusi yang lebih baik. - Jim W

Jwasch
sumber
0

Solusi sederhana di jQuery untuk mendeteksi penggunaan mouse, yang memecahkan masalah di mana perangkat seluler juga memicu acara 'mousemove'. Cukup tambahkan pendengar touchstart untuk menghapus pendengar mousemove, sehingga tidak terpicu saat disentuh.

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

Tentu saja, perangkat masih bisa menyentuh DAN mouse, tetapi di atas akan menjamin bahwa mouse asli digunakan.

suncat100
sumber
0

Baru saja menemukan solusi yang menurut saya cukup elegan.

// 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
    // ...
  }
});
Koala Yeung
sumber
0

Saya mengalami masalah yang sama, di mana satu sentuhan juga terdaftar sebagai klik. Setelah saya membaca komentar dari jawaban terpilih, saya datang dengan solusi saya sendiri:

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

Satu-satunya masalah yang saya temukan adalah, Anda harus dapat menggulir, untuk mendeteksi acara sentuh dengan benar. satu tab (sentuhan) dapat membuat masalah.

Jannis Nexor Ianus Betz
sumber
0

Saya menghabiskan waktu berjam-jam untuk mencari tahu masalah ini untuk aplikasi Phonegap saya dan saya membuat hack ini. Ini menghasilkan peringatan konsol jika acara yang dipicu adalah peristiwa "pasif", yang berarti tidak mengaktifkan perubahan apa pun, tetapi berhasil! Saya akan tertarik pada ide untuk meningkatkan atau metode yang lebih baik. Tetapi ini secara efektif memungkinkan saya untuk menggunakan $ .touch () secara universal.

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

Jay
sumber
0

masalah utama yang saya lihat di sini adalah bahwa sebagian besar perangkat sentuh menyalakan sebuah acara mouse bersama dengan sentuhan satu sentuhan (touchstart -> mousedown, touchmove -> mousemove, dll). Hanya untuk keyboard, akhirnya untuk yang modern, mereka memiliki browser generik sehingga Anda bahkan tidak dapat mendeteksi keberadaan kelas MouseEvent.

Solusi yang kurang menyakitkan di sini adalah, menurut pendapat saya, untuk menampilkan menu saat peluncuran (dengan manajemen 'alt' untuk pengguna keyboard saja) dan mungkin menyimpan pilihan dengan localStorage / cookies / serveride atau yang lain untuk menjaga pilihan yang sama berikutnya waktu pengunjung datang.

Ernoriel
sumber
-4

Saya sangat merekomendasikan menentang pendekatan ini. Pertimbangkan layar sentuh, perangkat berukuran desktop, dan Anda memiliki serangkaian masalah yang berbeda untuk dipecahkan.

Harap jadikan aplikasi Anda dapat digunakan tanpa mouse (yaitu, tidak ada pratinjau melayang).

Chris Broadfoot
sumber
1
Itulah tepatnya yang saya coba lakukan. Saya mencoba membuat antarmuka yang akan bekerja dengan cara terbaik di kedua tablet (tanpa mouse) dan dengan mouse, tetapi antarmuka tersebut tentu sangat berbeda.
Jon Gjengset
Saya setuju dengan broady. Anda paling baik menggunakan deteksi perangkat (seperti DeviceAtlas) dan pilih antarmuka yang ditawarkan pada waktu buka.
Teemu Ikonen
-4

Ingin merekomendasikan skrip yang membantu saya:

Saya telah membaca dan mencoba segala sesuatu yang disarankan, tanpa hasil yang memadai.

Lalu saya menyelidiki lagi, dan menemukan kode ini - device.js

Saya menggunakan ini di situs web klien saya, untuk mendeteksi keberadaan mouse:
( <html>seharusnya memiliki desktopkelas) dan sepertinya cukup bagus, dan untuk touchdukungan, saya hanya melakukan pemeriksaan rutin 'ontouchend' in documentdan menggunakan informasi dari kedua deteksi untuk mengasumsikan hal spesifik yang saya butuhkan.

vsync
sumber
Itu sama dengan mengendus UA, sudah diangkat berkali-kali dalam topik ini. Itu tidak menyelesaikan kasus perangkat dengan mouse DAN sentuhan seperti Windows 8, dan jelas bukan bukti masa depan.
Hugo Silva
Saya menggunakannya untuk menyelesaikan kasus EXACT ini yang Anda sebutkan dalam aplikasi klien dan berfungsi dengan baik. itu bukti masa depan, karena dikelola oleh pengembangnya.
vsync
2
Kasus yang saya sebutkan (sentuh laptop yang diaktifkan) akan diidentifikasi oleh skrip Anda sebagai "Desktop", meskipun saya tidak dapat menggunakan mouse. "ini adalah bukti masa depan, karena dikelola oleh pengembangnya" - Saya pikir Anda benar-benar kehilangan titik "bukti masa depan" di sini. Dan jika Anda telah membaca dan mencoba semuanya seperti yang Anda nyatakan, Anda akan memperhatikan bahwa jawaban Gigi sudah menyarankan untuk mengendus UA.
Hugo Silva
-7

Pada umumnya ide yang lebih baik untuk mendeteksi jika fungsi mouseover didukung daripada mendeteksi tipe OS / browser. Anda dapat melakukannya hanya dengan yang berikut:

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

Pastikan Anda tidak melakukan hal berikut:

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

Yang terakhir sebenarnya akan memanggil metode, daripada memeriksa keberadaannya.

Anda dapat membaca lebih lanjut di sini: http://www.quirksmode.org/js/support.html

Marcus Swope
sumber
2
Saya tidak benar-benar tahu harus mendapatkan apa dari pos Anda, tetapi jika ('onmouseover' dalam $ ('body') [0]) waspada ('onmouseover'); menampilkan pesan di iPhone juga
nraynaud
1
Ini hanya memeriksa apakah fungsi mouseover ditentukan, yang akan berada di hampir semua browser. Itu tidak mendeteksi apakah mouse benar-benar ada.
Jon Gjengset