Tarayıcının fare olmadığını ve yalnızca dokunmatik olduğunu algılama


149

Dokunmak için çok farklı bir arayüze (tıkladığınızda parmağınız ekranı gizler) ve fare (vurgulu önizlemeye büyük ölçüde dayanır) ile bir web uygulaması (ilginç metin sayfaları içeren bir web sitesi değil) geliştiriyorum. Kullanıcının ona doğru arayüzü sunmak için faresi olmadığını nasıl tespit edebilirim? Hem fare hem de dokunma özellikli insanlar için bir anahtar bırakmayı planlıyorum (bazı dizüstü bilgisayarlar gibi).

Tarayıcıdaki dokunma olayı özelliği, kullanıcının bir dokunmatik cihaz kullandığı anlamına gelmez (örneğin, Modernizr onu kesmez). Cihazda fare varsa, soruyu doğru yanıtlayan kod yanlış, aksi takdirde true döndürmelidir. Fare ve dokunma özelliğine sahip cihazlar için yanlış dönmelidir (yalnızca dokunma değil)

Bir yan not olarak, dokunmatik arayüzüm yalnızca klavyeye sahip cihazlar için de uygun olabilir, bu yüzden tespit etmek istediğim fare eksikliği daha fazla.

Gereksinimi daha açık hale getirmek için, uygulamak istediğim 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);


Bir uygulamanın hem masaüstü hem de mobil / dokunuş için geçerli olmasını, ancak her biri için farklı davranışlara sahip olmasını istiyorsanız tasarımınızı yeniden düşünmeniz gerektiğini düşünüyorum. Google'da "javascript tespit faresi" için yapılan hızlı bir arama, farenin çeşitli durumlarını (tıklamalar, konum, vb.), ancak SIFIR, farenin gerçekten var olup olmadığını gösterir.
davethegr8

24
Belki de Google, burada sorduğumda yardım etmediği için.
nraynaud

2
Jquery'den mouseenter dokümanını denediniz mi? $ (document) .mouseenter (function (e) {alert ("mouse");});
Parag Gajjar

4
Sadece bir dakika içinde her birini reddetmek için yaklaşık bir düzine umut vaat eden caddeyi düşündükten sonra, bu soru beni oldukça görkemli bir şekilde çıldırtıyor.
Jordan Grey

Yanıtlar:


65

Ana sorun, aşağıdaki farklı cihaz sınıflarına / kullanım durumlarına sahip olmanızdır:

  1. Fare ve tuş takımı (masaüstü)
  2. Yalnızca dokunma (telefon / tablet)
  3. Fare, klavye ve dokunma (dokunmatik dizüstü bilgisayarlar)
  4. Dokunmatik ve klavye (tablette bluetooth klavye)
  5. Yalnızca fare (Devre dışı bırakılmış kullanıcı / göz atma tercihi)
  6. Yalnızca klavye (Devre dışı bırakılmış kullanıcı / göz atma tercihi)
  7. Dokunmatik ve fare (yani Galaxy Note 2 kalemindeki fareyle üzerine gelme olayları)

Daha da kötüsü, bu sınıflardan bazılarından başkalarına geçebilir (faredeki fişler, klavyeye bağlanır) veya bir kullanıcı ekrana ulaşana ve ekrana dokunana kadar normal bir dizüstü bilgisayarda görünebilir.

Tarayıcıda olay oluşturucuların varlığının ilerlemenin iyi bir yolu olmadığını (ve biraz tutarsız olduğunu) varsayarsınız. Ayrıca, çok özel bir etkinliği izlemiyorsanız veya yalnızca birkaç sınıfı hariç tutmaya çalışmıyorsanız, etkinliklerin kendilerinin kullanılması tam bir kanıt değildir.

Örneğin, bir kullanıcının gerçek bir fare imleci yaydığını keşfettiğinizi varsayalım (dokunma etkinliklerinden yanlış olanı değil, bkz. Http://www.html5rocks.com/en/mobile/touchandmouse/ ).

Sonra ne?

Fareyle üzerine gelme stilleri etkinleştirilsin mi? Daha fazla düğme mi ekliyorsunuz?

Her iki durumda da cam zamanını arttırıyorsunuz çünkü bir olayın ateşlenmesini beklemek zorundasınız.

Ama sonra asil kullanıcınız faresini çıkarıp tam dokunuşa karar vermek istediğinde ne olur .. şimdi tıka basa dolu arayüzünüze dokunmasını bekler misiniz, sonra şimdi kalabalık kullanıcı arayüzünüzü saptamak için çaba gösterdikten hemen sonra değiştirir misiniz?

Bullet formunda, stucox'tan https://github.com/Modernizr/Modernizr/issues/869#issuecomment-15264101 adresinden alıntı yapılır.

  • Bir farenin varlığını tespit etmek istiyoruz
  • Ae bir olay başlatılmadan önce muhtemelen tespit edemez
  • Bu nedenle, tespit ettiğimiz şey, bu oturumda bir fare kullanılmışsa - sayfa yükünden hemen sonra olmayacak
  • Muhtemelen bir fare olmadığını da tespit edemeyiz - doğru olana kadar tanımsız olurdu (bence bu kanıtlanana kadar yanlış ayarlamaktan daha mantıklı)
  • Ve muhtemelen bir farenin oturum ortasında bağlantısının kesilip kesilmediğini tespit edemeyiz - bu, fareden vazgeçen kullanıcıdan ayırt edilemez

Bir kenara: tarayıcı bir kullanıcı bir fare taktığında / bir klavyeye bağlandığında biliyor, ama JavaScript'e maruz bırakmıyor .. dang!

Bu sizi aşağıdakilere yönlendirmelidir:

Belirli bir kullanıcının mevcut yeteneklerini izlemek karmaşık, güvenilmez ve şüpheli bir değerdir

Bununla birlikte, ilerici gelişme fikri burada oldukça iyi uygulanmaktadır. Kullanıcının bağlamı ne olursa olsun sorunsuz çalışan bir deneyim oluşturun. Ardından, varsayılan bağlamda göreceli işlevler eklemek için tarayıcı özelliklerine / medya sorgularına dayalı varsayımlar yapın. Bir farenin varlığı, farklı cihazlardaki farklı kullanıcıların web sitenizi deneyimlemesinin çok çeşitli yollarından biridir. Çekirdeğinde liyakat ile bir şeyler yaratın ve insanların düğmeleri nasıl tıkladıkları konusunda fazla endişelenmeyin.


3
mükemmel cevap. Umarım, kullanıcının her zaman bir ekranı vardır! Kullanıcının mevcut etkileşim moduna göre bir arayüz oluşturmak mantıklı olduğunu düşünüyorum. Dokunmatik bir dizüstü bilgisayarda, :hoverkullanıcı fareden dokunmaya geçtiğinde uygulamayı (yani öğeler ve bunun gibi şeyler) ayarlamak mantıklıdır . Kullanıcının şu anda aynı anda fare + dokunmatik kullanması pek olası görünmüyor (yani, aynı bilgisayara bağlı 2 fareye sahip olmak gibi)
Sebastien Lorber

@SebastienLorber - Sana kırmak istemem ancak kullanıcıların yok ille her zaman bir ekran var. ( Bir ekran okuyucunun bir kullanıcı makinesinde çalışıp çalışmadığını tespit etmek için javascript kullanmak mümkün mü? )
ashleedawg

57

Belgede fareyle üzerine gelme olayını dinlemeye ne dersiniz? Ardından bu olayı duyana kadar cihazın yalnızca dokunma veya klavye olduğunu varsayarsınız.

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

(Nerede listenve uygun veya uygun şekilde unlistentemsilci seçebiliriz.)addEventListenerattachEvent

Umarım bu çok fazla görsel sarsıntıya yol açmaz, moda dayalı büyük yeniden düzenlere ihtiyacınız varsa emer ...


2
Bu iyi bir fikir, ancak maalesef, uygulamanın kullanıcı arayüzü bir farenin kullanılabilir olup olmadığına bağlı olduğunda, yanıttaki gecikme kullanılamaz hale gelecek. fare iframe kendisi üzerinde hareket ..
Jon Gjengset

7
Bu, uygulama bir açılış ekranı ve "devam" düğmesiyle başlarsa işe yarayabilir. Fare ilk fareyle üzerine gelmeden önce hareket ederse fareniz olur. Yalnızca doğrudan farenin altına yüklenen ve kullanıcının çok sabit bir eli varsa başarısız olur (1 piksel hareket etse bile alınmalıdır).
SpliFF

49
güzel bir fikir, ama testimizde işe yaramıyor gibi görünüyor . iPad'ler bu etkinliği tetikler.
Jeff Atwood

3
@JeffAtwood Davanızda ne yaptınız?
Michael Haren

2
iPad'ler, fareyle üzerine gelme olayından hemen önce fareyle üzerine gelme etkinliğini tetikler. Farenin sayısını> 0 ve farenin sayısını == farenin sayısının fare algılamak için iyi bir yol olduğunu gördüm. Bunu gerçek bir fare ile çoğaltamıyorum.
Peter Wooster

36

2018'den itibaren bir tarayıcının bir fareye (veya benzer bir giriş cihazına) sahip olup olmadığını tespit etmenin iyi ve güvenilir bir yolu vardır: CSS4 medya etkileşimi özellikleri hemen hemen tüm modern tarayıcılar tarafından desteklenmektedir (IE 11 ve özel mobil tarayıcılar hariç).

W3C:

İşaretçi ortam özelliği, fare gibi bir işaretleme aygıtının varlığını ve doğruluğunu sorgulamak için kullanılır.

Aşağıdaki seçeneklere bakın:

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

Medya sorguları JS'de de kullanılabilir:

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

İlişkili:

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

Tarayıcı desteği: https://caniuse.com/#search=media%20features

Benzer sorun: Bir istemci cihazın destekleyip desteklemediğini tespit edin: üzerine gelin ve: odak durumları


Ben şahsen bu yanıtı beğendim ama şu andan itibaren (10/19), @media hover ve pointer CSS sorguları dünya çapındaki cihazların sadece ~ 85% 'inde mevcut. Kesinlikle kötü değil,% 95 veya üstü tercih edilir. Umarım bu yakında cihazlarda standart hale gelir.
MQuiggGeorgia

1
@MQuiggGeorgia Temel olarak eleştirilerinize katılıyorum, henüz her yerde desteklenmiyor. Hala benim için caniuse.com% 91.2 desteklendiğini söylüyor ( caniuse.com/#feat=css-media-interaction ). Daha yakından bakıldığında, IE 11 ve mobil cihazlarda özel düzleştirilmiş tarayıcılar dışında her yerde desteklenir. Adil olmak gerekirse, Microsoft uzun zamandır IE özelliklerini uygulamayı bıraktığından, bu modern özellikler için geçerlidir. IE 11 için buradaki diğer cevaplardan bir geri dönüş kullanabilirsiniz.
Blackbam

23

@ Wyatt'ın cevabı harika ve bize düşünecek çok şey veriyor.

Benim durumumda, ancak daha sonra bir davranış ayarlamak için ilk etkileşimi dinlemeyi seçtim. Bu nedenle, kullanıcının bir faresi olsa bile, ilk etkileşim bir dokunuşsa dokunmatik cihaz olarak ele alacağım.

Olayların işlendiği verilen sipariş dikkate alındığında :

  1. touchstart
  2. touchmove
  3. touchEnd
  4. mouseover
  5. mousemove
  6. mousedown
  7. mouseup
  8. Tıklayın

Fare olayı dokunmadan önce tetiklenirse, bunun taklit değil gerçek bir fare olayı olduğunu varsayabiliriz. Örnek (jQuery kullanarak):

$(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);
});

Bu benim için çalıştı


Benim için çalışmıyor, Ipad Safari (IOS8.3) de bu
pasajla

3
@netzaffin. Geri bildiriminiz için teşekkürler, fareyle üzerine gelmek yerine fareyle kullanımın daha tutarlı olduğunu gördüm. Bu kemana IOS'nuzdan bakar ve sonucu bana bildirir misiniz? Şerefe jsfiddle.net/bkwb0qen/15/embedded/result
Hugo Silva

1
Fareli bir dokunmatik ekranınız varsa, yalnızca önce kullanılan giriş yöntemi algılanacaktır.
0xcaff

11

Yalnızca bir tarayıcının dokunma özelliğine sahip olup olmadığını tespit etmek mümkündür . Bir dokunmatik ekrana veya fareye bağlı olup olmadığını bilmenin bir yolu yok.

Dokunmatik özelliği algılanırsa fare olayı yerine dokunma olayını dinleyerek kullanıma öncelik verilebilir.

Çapraz tarayıcı tarayıcı özelliğini algılamak için:

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

Sonra bunu kontrol etmek için kullanabilirsiniz:

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

veya hangi etkinliği dinleyeceğinizi seçmek için:

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

veya dokunma ve dokunmama için ayrı yaklaşımlar kullanın:

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
}

Fare için kişi, farenin kullanılıp kullanılmadığını algılayabilir, var olup olmadığını algılamaz. Farenin kullanım tarafından algılandığını göstermek için genel bir bayrak ayarlanabilir (mevcut bir cevaba benzer, ancak biraz basitleştirilmiş):

var hasMouse = false;

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

( bu etkinlik dahil edilemez mouseupveya mousedownbu etkinlik dokunarak da tetiklenebilir)

Tarayıcılar, kullanıldığı sistemin donanım özellikleri gibi özellikleri algılayabilmek için gereken düşük düzeyli sistem API'lerine erişimi kısıtlar.

Bunlara erişmek için belki bir eklenti / uzantı yazma olasılığı vardır, ancak JavaScript ve DOM aracılığıyla bu algılama bu amaç için sınırlıdır ve çeşitli işletim sistemi platformlarına özgü bir eklenti yazmak zorunda kalacaktır.

Sonuç olarak: böyle bir tespit ancak “iyi bir tahmin” ile tahmin edilebilir.


8

Ne zaman Medya Sorguları Seviye 4 tarayıcılarda kullanılabilir, bir fare ile cihazları algılamasına "işaretçi" ve "vurgulu" sorguları kullanmak mümkün olacak.

Bu bilgileri gerçekten Javascript'e iletmek istiyorsak, cihaz tipine göre belirli stilleri ayarlamak için bir CSS sorgusu kullanabilir ve ardından getComputedStylebu stili okumak ve orijinal cihaz tipini türetmek için Javascript'te kullanabiliriz .

Ancak bir fare herhangi bir zamanda bağlanabilir veya çıkarılabilir ve kullanıcı dokunma ve fare arasında geçiş yapmak istiyor olabilir. Bu nedenle , bu değişikliği tespit etmemiz ve arayüzü değiştirmeyi veya otomatik olarak yapmayı teklif etmemiz gerekebilir .


1
Özellikle, any-pointerveany-hover yürürlükteki tüm cihaz özelliği araştırmak izin verir. Gelecekte bu sorunu nasıl çözebileceğimize bir göz atmak güzel! :)
Jordan Gray

2
window.matchMedia ("(herhangi bir işaretçi: kaba)"). match === true?
4esn0k

7

Yine de arabirimler arasında geçiş yapmanın bir yolunu sunmayı planladığınızdan, kullanıcıdan uygulamanın doğru sürümünü "girmek" için bir bağlantıyı veya düğmeyi tıklatmasını istemek mümkün mü? Ardından, gelecekteki ziyaretler için tercihlerini hatırlayabilirsiniz. Yüksek teknoloji değil, ancak% 100 güvenilir :-)


2
Aslında oldukça iyi bir öneri, ancak kullanıcının gerçek arayüze ulaşması için geçen süreyi geciktiriyor. Ayrıca, ilk seçimden sonra geçiş yapmanın bir yolunu sağlamak zorundayım. Basitçe tespit edilenden daha fazla iş biter ..
Jon Gjengset

1
Kullanıcıya sormak en iyi yoldur - her zaman kusursuz değilse - Ve size yükseltme bildirimlerini koymak için uygun bir yer verir ve ne değil. Bence "problemi" düşünüyorsun ..
T4NK3R

4

@SamuelRossille Maalesef bir farenin varlığını (veya eksikliğini) ortaya çıkardığının farkında olduğum tarayıcı yok.

Öyleyse, bununla birlikte, mevcut seçeneğimiz ... etkinliklerle elimizden gelenin en iyisini yapmaya çalışmalıyız. Tam olarak aradığın şey olmadığını biliyorum ... şu anda ideal olmaktan uzak olduğunu kabul etti.

Kullanıcının herhangi bir anda fare mi yoksa dokunma kullanıp kullanmadığını anlamak için elimizden geleni yapabiliriz. İşte jQuery & Knockout kullanarak hızlı ve kirli bir örnek:

//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');

Artık usingMouse () & usingTouch () yöntemini bağlayabilir / abone olabilir ve / veya arayüzünüzü body.mouse sınıfıyla şekillendirebilirsiniz . Arayüz, bir fare imleci algılanır algılanmaz ve dokunulduğunda başlar.

Umarım yakında tarayıcı satıcılarından daha iyi seçeneklerimiz olur.


2

Tera-WURFL , tarayıcı imzasını veritabanıyla karşılaştırarak sitenizi ziyaret eden cihazın yeteneklerini size söyleyebilir . Bir göz atın, ücretsiz!


1
Bu, dokunmatik ekranlara ve bir fareye sahip olan veya olmayan cihazlar için çalışmaz. Örneğin, bir masaüstü Windows bilgisayar bir dokunmatik ekrana bağlanabilir, ancak genellikle bir fareye sahip olurken, bir tablet de Windows çalıştırıyor olabilir, ancak bir fare bağlı olmayabilir ..
Jon Gjengset

@Jonhoo Masaüstü işletim sistemlerinde bir fare takılı olduğunu varsayalım. Sonuçta, bir dokunmatik ekran düşünülerek geliştirilmemiş çok çeşitli yazılımları desteklemelidirler.
Gigi

1
Düz Windows 8 çalıştıran tabletlere ne dersiniz? Yoksa Linux mu? Veya Android çalıştıran dizüstü bilgisayarlar?
Jon Gjengset

2
@Jonhoo Açıkçası bu yaklaşım optimalden daha azdır, ancak bunu bilmenin taşınabilir bir yolu yoktur (henüz). Biri Android ile bir dizüstü bilgisayar çalıştırıyorsa, dokunmatik özellikli olduğunu varsayalım. Biri Windows8 tablet çalıştırıyorsa, farenin fareyle uyumlu olduğunu varsayalım (işletim sisteminin dokunmatik olmayan programlar için fareyi taklit etmesi gerekir).
Gigi

Bu artık o kadar güncel değil ki artık geçerli değil.
Mühendis

2

Neden sadece dokunuşları algılama ve / veya fare hareketlerine tepki verme yeteneğine sahip olduğunu tespit etmiyorsunuz?

// 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
Çünkü bazı tarayıcılar (örneğin IE9), hiçbir zaman tetiklenmeyecek olsa bile işlevin var olduğunu bildirir. Bunun da "doğru" davranış olduğuna inanıyorum.
Jon Gjengset

neden bir fonksiyon kullanasın ki? sadece has_touch = 'ontouchstart' in windowyeterli olacak, vb.
vsync

En azından OS X için Chrome 47'de çalışıyor. Başlama yok bildiriliyor.
phreakhead

2

Bu benim için benzer bir durumda işe yaradı. Temel olarak, farelere veya farelere müdahale etmeden kısa bir ardıl fare kapanı serisi görene kadar kullanıcının bir faresi olmadığını varsayalım. Çok zarif değil, ama işe yarıyor.

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'e bir göz atın özelliklerinden biri dokunmatik

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

Tam olarak test etmeme rağmen çok iyi çalışıyor gibi görünüyor

Ayrıca bu, http://www.html5rocks.com/en/mobile/touchandmouse/ modernizr sayfasından da bağlantılıdır.


Bu, SADECE dokunma olup olmadığını ve fare yeteneği olup olmadığını değil, dokunma yeteneğini algılamaya çalışır. Bu soru temel olarak dokunma algılamasından farklıdır.
Jimbo Jonny

0

Diğerlerinin de belirttiği gibi, bir fareye sahip olup olmadıklarını kesin olarak tespit etmek güvenilir değildir. Bu, cihaza bağlı olarak kolayca değişebilir. Kesinlikle en azından belge ölçeğinde boolean true veya false ile güvenilir bir şekilde yapamayacağınız bir şey.

Dokunmatik etkinlikler ve fare etkinlikleri özeldir. Bu, farklı eylemler gerçekleştirmeye biraz yardımcı olabilir. Sorun, dokunma olaylarının fare yukarı / aşağı / taşıma olaylarına daha yakın olması ve ayrıca bir tıklama olayını tetiklemesidir.

Sorunuzda, önizlemek için bir fareyle üzerine gelmek istediğinizi söylüyorsunuz. Bunun ötesinde arayüzünüzle ilgili başka bir ayrıntı bilmiyorum. Ben ediyorum varsayarak bir tık nedeniyle vurgulu önizleme farklı bir eylem yapar iken, önizleme için musluklarını istediğiniz bir fare eksikliği olduğunu.

Bu durumda, tespit için biraz tembel bir yaklaşım kullanabilirsiniz:

Bir onclick olayından önce her zaman bir fare ile büyük bir olay gerçekleşir. Bu nedenle, farenin tıklanan öğenin üstünde olduğuna dikkat edin.

Bunu belge çapında bir olayla yapabilirsiniz. event.targetFarenin hangi öğede bulunduğunu kaydetmek için kullanabilirsiniz . Ardından, onclick etkinliklerinizin içinde farenin gerçekten tıklanan öğenin (veya öğenin alt öğesinin) üzerinde olup olmadığını kontrol edebilirsiniz.

Buradan, her ikisi için de tıklama etkinliğine güvenmeyi ve sonuca bağlı olarak bir A veya B eylemi gerçekleştirmeyi seçebilirsiniz. Bazı dokunmatik cihazlar bir tıklama etkinliği yayınlamazsa B işlemi hiçbir şey yapamaz (bunun yerine üzerine * etkinliklere güvenmeniz gerekir).


0

Sadece dokunmatik cihazı tanımlamanın mümkün olduğunu düşünmüyorum (tabii ki bilgime göre). Ana sorun, tüm fare ve klavye olaylarının dokunmatik cihazlar tarafından da başlatılmasıdır. Aşağıdaki örneğe bakın, her iki uyarı da dokunmatik cihazlar için doğrudur.

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 döner ipad trueiçin'onmousedown' in window
vsync

0

Bence en iyi fikir mousemovedinleyicidir (şu anda en iyi cevap). Bu yöntemin biraz düzeltilmesi gerektiğine inanıyorum. Bu iOS tartışmasında görebileceğiniz gibi, dokunmatik tabanlı tarayıcıların fareyle üzerine gelme olayını bile taklit ettiği doğrudur , bu yüzden biraz dikkatli olmalıyız.

Dokunmatik tabanlı tarayıcıların bu olayı yalnızca kullanıcı ekrana dokunduğunda (kullanıcının parmağı aşağıdayken) taklit etmesi mantıklıdır. Bu, etkinlik sırasında hangi fare düğmesinin (varsa) basılı olduğunu görmek için fareyle üzerine gelme işleyicimiz sırasında bir test eklememiz gerektiği anlamına gelir. Hiçbir fare düğmesi basılı değilse, gerçek bir farenin var olduğunu güvenle varsayabiliriz. Fare düğmesi basılıysa, test sonuçsuz kalır.

Peki bu nasıl uygulanacak? Bu soru , bir fare tekerleği sırasında hangi fare düğmesinin kapalı olduğunu incelemenin en güvenilir yönteminin belge düzeyinde 3 olayı dinlemek olduğunu gösterir: fare tekerleği, fareyle üzerine gelme ve fare ile. Yukarı ve aşağı sadece küresel bir boole bayrağı koyacaktır. Hareket testi gerçekleştirir. Bir hareketiniz varsa ve boolean yanlışsa, bir farenin var olduğunu varsayabiliriz. Kesin kod örnekleri için soruya bakın.

Son bir yorum .. Bu test ideal değildir çünkü yükleme zamanında gerçekleştirilemez. Bu nedenle, daha önce önerildiği gibi aşamalı bir geliştirme yöntemi kullanacağım. Varsayılan olarak, fareye özgü fareyle üzerine gelme arabirimini desteklemeyen bir sürümü gösterir. Bir fare bulunursa, JS kullanarak çalışma zamanında bu modu etkinleştirin. Bu, kullanıcı için olabildiğince kesintisiz görünmelidir.

Kullanıcının yapılandırmasındaki değişiklikleri desteklemek için (yani fare bağlantısı kesildi), periyodik olarak yeniden test edebilirsiniz. Her ne kadar bu durumda kullanıcıyı 2 mod hakkında bilgilendirmek ve kullanıcıların aralarında manuel olarak geçiş yapmasına izin vermenin daha iyi olacağına inanmama rağmen (her zaman tersine çevrilebilen mobil / masaüstü seçimi gibi).


Teşekkürler orada iyi geçici çözüm önerileri ... Bence ana sorun sovled değil Bunlardan birini başvurmak zorunda
kalacak

Ne yazık ki mousemove bir ipad tıklama tetiklenir. Sadece simülatör ile test edildi. HasMouse () için if (! ('Ontouchstart' penceresinde)) true döndürürse kullanıyordum; ancak dokunmatik destekli dizüstü bilgisayarlarda çalışmaz.
Chris Gunawardena

@Chris G - iPad cehennem ... (başımı duvara vurarak)
vsync

0

Çeşitli bilgisayarlarda, Linux'larda, iPhone'da, Android telefonlarda ve sekmelerde bazı testler yaptık. Kurşun geçirmez kolay bir çözüm olmaması garip. Dokunmatik olan ve hala fare olmayan bazı uygulamalara Dokunmatik ve Fare olayları olduğunda sorun ortaya çıkar. Yalnızca fare ve yalnızca dokunma örneklerini desteklemek istediğinden, her ikisini de işlemek istersiniz, ancak bu, kullanıcı etkileşimlerinin iki kez tekrarlanmasına neden olur. Farenin cihazda olmadığını bilebilirseniz, sahte / takılı fare olaylarını yoksaymayı bilebilir. MouseMove ile karşılaşılırsa ayar bayrağı denendi, ancak bazı tarayıcılar MouseUp ve MouseDown gibi sahte MouseMove atar. Zaman damgalarını incelemeye çalıştım, ancak bunun çok riskli olduğunu düşündüm. Alt satır: Sahte fare olaylarını oluşturan tarayıcıları, eklenen MouseDown'dan hemen önce her zaman tek bir MouseMove ekledim. Vakalarımın% 99,99'unda, gerçek bir fareye sahip bir sistemde çalışırken, en az iki ardışık MouseMove olayı vardır. Bu nedenle, sistemin iki ardışık MouseMove olayıyla karşılaşıp karşılaşmadığını takip edin ve bu koşul asla karşılanmazsa hiçbir fare olmadığını beyan edin. Bu muhtemelen çok basit, ama tüm test kurulumlarım üzerinde çalışıyor. Daha iyi bir çözüm bulana kadar buna bağlı kalacağımı düşün. - Jim W


0

JQuery'de fare kullanımını algılamak için basit bir çözüm, bu da mobil cihazların 'fare kaldırma' olayını tetiklediği sorunu çözüyor. Fareyle üzerine gelme dinleyicisini kaldırmak için dokunmaya duyarlı bir dinleyici eklemeniz yeterlidir, böylece dokunulduğunda tetiklenmez.

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

Tabii ki, cihaz hala dokunmatik VE fare olabilir, ancak yukarıdakiler gerçek bir farenin kullanıldığını garanti edecektir.


0

Sadece oldukça zarif olduğunu düşündüğüm bir çözüm buldum.

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

Tek bir dokunuşun da tıklama olarak kaydedildiği aynı sorunla karşılaştım. En çok oy alan cevapların yorumlarını okuduktan sonra kendi çözümümü buldum:

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

Bulduğum tek sorun, bir dokunma olayını doğru bir şekilde algılamak için kaydırma yapabilmeniz gerektiğidir. tek bir sekme (dokunma) sorun yaratabilir.


0

Phonegap uygulamam için bu sorunu çözerek saatler harcadım ve bu hack ile geldim. Tetiklenen olay bir "pasif" olay ise bir konsol uyarısı oluşturur, yani herhangi bir değişikliği harekete geçirmez, ancak çalışır! Geliştirmek için herhangi bir fikir veya daha iyi bir yöntem ile ilgilenirim. Ama bu etkili bir şekilde $ .touch () yöntemini evrensel olarak kullanmamı sağlıyor.

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

Burada gördüğüm temel sorun, çoğu dokunmatik cihazın karşılık gelen dokunuşla bir fare olayı (touchstart -> mousedown, touchmove -> mousemove, vb.) Sadece klavye olanlar için, nihayet modern olanlar için, genel bir tarayıcıları vardır, böylece MouseEvent sınıfının varlığını bile tespit edemezsiniz.

Buradaki daha az acı verici bir çözüm, bence, açılışta bir menü görüntülemek (sadece klavye kullanıcıları için 'alt' yönetimi ile) ve belki de localStorage / çerezler / sunucularda seçim yapmak veya aynı seçimi bir sonraki tutmak için ziyaretçinin geldiği zaman.


-4

Bu yaklaşıma karşı şiddetle tavsiye ediyorum. Dokunmatik ekran, masaüstü boyutunda aygıtları düşünün ve çözmeniz gereken farklı sorunlar var.

Lütfen uygulamanızı faresiz kullanılabilir hale getirin (fareyle üzerine gelindiğinde önizleme yapılmaz).


1
Kesinlikle yapmaya çalıştığım şey bu. Her iki tablet (fare olmadan) ve bir fare ile mümkün olan en iyi şekilde çalışacak bir arabirim oluşturmaya çalışıyorum, ancak bu arabirimler mutlaka çok farklı.
Jon Gjengset

Geniş görüşe katılıyorum. Cihaz algılama (DeviceAtlas gibi) kullanarak ve yükleme sırasında sunulan arayüzü seçerek en iyisi olursunuz.
Teemu Ikonen

-4

Bana yardımcı olan bir komut dosyası önermek isterim:

Yeterli sonuçlar olmadan önerilen her şeyi okudum ve denedim.

Sonra biraz daha araştırdım ve bu kodu buldum - device.js

Bunu fare varlığını tespit etmek için müvekkilimin web sitesinde kullanıyorum:
( sınıf <html>olmalı desktop) ve oldukça iyi görünüyor ve touchdestek için, sadece düzenli kontrol yapmak ve 'ontouchend' in documentihtiyacım olan belirli bir şey varsayalım her iki algılama bilgilerini kullanın.


Bu zaten bu konuda birçok kez gündeme getirilen UA kokusuna eşdeğer. Fare ve cihazların Windows 8 gibi dokunma durumunu çözmez ve kesinlikle geleceğin kanıtı değildir.
Hugo Silva

Bir müşterinin uygulamasında bahsettiğiniz bu TAM davayı çözmek için kullanıyorum ve iyi çalışıyor. geleceğin kanıtıdır, çünkü geliştiricisi tarafından korunur.
vsync

2
Bahsettiğim vaka (dokunmatik özellikli dizüstü bilgisayar), bir fare kullanmasam bile betiğiniz tarafından "Masaüstü" olarak tanımlanacaktı. "Geleceğin kanıtı, çünkü geliştiricisi tarafından korunuyor" - Sanırım burada "gelecekteki kanıtı" konusunu tamamen kaçırdınız. Ve belirttiğiniz gibi her şeyi okuyup denediyseniz, Gigi'nin cevabının zaten UA koklamasını önerdiğini fark ederdiniz.
Hugo Silva

-7

OS / tarayıcı türünü algılamak yerine fareyle üzerine gelme işlevinin desteklenip desteklenmediğini tespit etmek genellikle daha iyi bir fikirdir. Bunu sadece aşağıdakileri yaparak yapabilirsiniz:

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

Aşağıdakileri yapmadığınızdan emin olun :

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

İkincisi aslında varlığını kontrol etmek yerine yöntemi çağırır.

Daha fazla bilgiyi buradan edinebilirsiniz: http://www.quirksmode.org/js/support.html


2
Gönderinizden ne alacağımı gerçekten bilmiyorum, ancak ($ ​​('body') [0]) '(' onmouseover ')' de 'onmouseover'); iPhone'da da bir mesaj görüntüler
nraynaud

1
Bu yalnızca fareyle üzerine gelme işlevinin tanımlanıp tanımlanmadığını kontrol eder; bu işlev hemen hemen tüm tarayıcılarda olacaktır. Bir farenin gerçekten var olup olmadığını algılamaz.
Jon Gjengset
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.