'Touchstart' ve 'click' etkinliklerini nasıl bağlar, ancak her ikisine de yanıt vermez?


200

Çeşitli cihazlarda çalışması gereken bir mobil web sitesinde çalışıyorum. Şu an bana başım ağrıyor BlackBerry.

Hem klavye tıklamalarını hem de dokunma etkinliklerini desteklememiz gerekir.

İdeal olarak sadece şunu kullanırdım:

$thing.click(function(){...})

ancak karşılaştığımız sorun, bu böğürtlen cihazlarının bazılarının dokunma anından tıklamayı tetikleyen çok can sıkıcı bir gecikmeye sahip olmasıdır.

Çözüm bunun yerine touchstart kullanmaktır:

$thing.bind('touchstart', function(event){...})

Ama her iki olayı da bağlarım, ama sadece bir olayı nasıl tetiklerim? Klavye aygıtları için yine de tıklama etkinliğine ihtiyacım var, ancak elbette, bir dokunmatik cihaz kullanıyorsanız tıklama etkinliğinin tetiklenmesini istemiyorum.

Bonus bir soru: Bunu yapmak ve ayrıca bir touchstart etkinliği bile olmayan tarayıcıları barındırmak için yine de var mı? Bunu araştırırken, BlackBerry OS5 dokunmatik başlatmayı desteklemiyor gibi görünüyor, bu nedenle o tarayıcı için tıklama etkinliklerine de güvenmeniz gerekecek.

EK:

Belki daha kapsamlı bir soru:

JQuery ile aynı temaslarla hem dokunmatik etkileşimleri hem de fare etkileşimlerini ele almak mümkün mü / tavsiye ediliyor mu?

İdeal olarak, cevap evettir. Değilse, bazı seçeneklerim var:

1) Cihaz bilgisini almak için WURFL kullanıyoruz, böylece kendi cihaz matrisimizi oluşturabiliriz. Cihaza bağlı olarak, touchstart VEYA click'i kullanacağız.

2) JS üzerinden tarayıcıda dokunmatik destek için algılama (Bu konuda biraz daha araştırma yapmam gerekiyor, ancak bu yapılabilir gibi görünüyor).

Ancak, bu hala bir sorun bırakıyor: Peki BOTH'u destekleyen cihazlar. Desteklediğimiz telefonlar (yani Nokianın ve BlackBerries) Bazı dokunmatik ekranlar her ikisine de sahip ve klavyeler. Yani bu tür bir soru beni tam anlamıyla orijinal soruya geri götürüyor ... Her ikisine de aynı anda izin vermenin bir yolu var mı?


2
Touchstart ve touchend'e bağlanıp dokunma mantığınızın yanında kendi tıklama mantığınızı yazmanız daha iyi olur. Yerleşik tıklama geri çağırma dokunuş bilgisi yok.
Justin808

Takip ettiğimden emin değilim, Justin. Hâlâ ona bağlı bir dokunmatik başlatma ve tıklama etkinliğine sahip olmaz mıydım?
DA.

@DA - hayır, .click () geri aramasına hiç bağlanmazsınız. Bazı sudo kodlarında bir cevap yazmaya çalışacağım. Gerçek kod yazmak için kullanışlı bir dokunmatik cihazım yok :)
Justin808

Ah, ama açıklığa kavuşturmak için hala tıklama etkinliklerine ihtiyacım var, çünkü bu siteye dokunmatik olmayan cihazlarla erişen insanlar olacak.
DA.

2
Kullanmak .bind('touchstart mouseup')bunu çözecektir (aşağıdaki yorumlardan birine dayanarak)
oriadam

Yanıtlar:


136

Güncelleme : Mouse ve touch arasında seçim yapmak yerine "pointer" olaylarına bağlanmanıza izin veren jQuery Pointer Events Polyfill projesine göz atın .


Her ikisine de bağlanın, ancak fonksiyon her 100 ms'de bir kez ateşlenecek şekilde bir bayrak yapın.

var flag = false;
$thing.bind('touchstart click', function(){
  if (!flag) {
    flag = true;
    setTimeout(function(){ flag = false; }, 100);
    // do something
  }

  return false
});

7
hmm ... kibirli hissettiriyor, ama bu işe yarayabilir. Yakalama, bu cihazların bazılarında, fark edilebilir bir gecikme ... belki de neredeyse bir saniye ... daha hızlı bir cihazda başkaları için can sıkıcı olacaktır.
DA.

15
clickDeğiştirmek yerine kullanmak mousedown... belki uzun gecikme arasındaki farktır mousedownve mouseupa arasındaki fark clickbudur.
Mottie

7
Bu benim gittiğim çözüm. Teşekkürler! Ben touchendbir sınıf uygulayarak bir öğeyi işaretlemek olduğunu touched. Bu, click olayı çağrılmadan önce tetiklenir. Sonra ilk önce o sınıfın varlığını kontrol eden bir click olayı eklerim. Oradaysa, dokunma olaylarının tetiklendiğini varsayarız ve bir sonraki etkileşim için 'sıfırlamak' için sınıf adını kaldırmak dışında tıklama ile hiçbir şey yapmayız. Sınıf orada değilse, öğeyi tıklamak ve işlevi oradan tetiklemek için bir klavye kullandıklarını varsayıyoruz.
DA.

7
Çoğu telefon tarayıcısının tıklama olayında 300ms gecikme olduğunu bilmeniz gerekir, bu nedenle deleay'yi en az 300'e çıkarmalısınız , 300ms gecikme sorunuyla ilgili bu makaleye bakın . Bu, temel olarak, çoğu web sitesinin büyük bir masaüstü ekranında görüntülemek üzere tasarlandığı erken iPhone günlerinde çok önemli bir özellik olan "yakınlaştırmak için çift tıklama" işlevini etkinleştirmektir.
korku

12
Bu soru bu noktada 100 bin'e yakın kez incelendi. Bu olağanüstü yaygın bir kullanım durumu / sorunu gibi görünüyor. Bununla birlikte, bu cevap ve bu ve benzeri sorulardaki diğerleri hacky görünüyor. Google çözümü, çoğundan daha ayrıntılı bir şekilde düşünülmüş olsa da, sadece daha sağlam bir saldırı gibi görünüyor. Bir tıklama işleyici kadar basit bir şey için, çözüm basit olmalı gibi görünüyor. Kimse bu sorun için hack olmayan bir çözüm bulamadı mı?
jinglesthula

73

Bu "oluşturduğum" düzeltmedir ve GhostClick'i çıkarır ve FastClick'i uygular. Kendi başınıza deneyin ve sizin için işe yarayıp yaramadığını bize bildirin.

$(document).on('touchstart click', '.myBtn', function(event){
        if(event.handled === false) return
        event.stopPropagation();
        event.preventDefault();
        event.handled = true;

        // Do your magic here

});

2
helgatheviking: jsbin.com/ijizat/25 JavaScript'te yukarıdakileri içeren TouchClick adlı bir işlev vardır.
Matt Parkins

5
Bu sorunun tüm cevapları için bu yöntemi tercih ederim, çünkü a) cihaz yeteneklerini test etmiyor ve b) setTimeout kullanmıyor. Deneyimlerime göre, setTimeout kullanan bu gibi sorunların çözümleri çoğu durumda işe yarayabilir, ancak olayların zamanlaması oldukça keyfi ve cihaza özeldir.
itsmequinn

7
Bu işe yaramaz, çünkü anonim işlevde 'event' iletilerek bu işlev içinde yerel bir nesne olur, dolayısıyla olay her tetiklendiğinde event.handledeşit undefinedolur. İşte bir çözüm: kullanarak hedef öğenin kendisinde 'işlenen' bayrağı ayarlayın jQuery.data().
thdoan

3
Sen var event.stopPropagation();ve event.preventDefault();benim anlayış (ve test) olay sadece bununla kez ateş edilebilir. Öyleyse neden kontrol if(event.handled !== true)ediyorsun? Benim için gerekli değil mi yoksa bir şey mi özlüyorum?
nbar

2
event.handledDeğer kontrol edilmemeli truemi? Asla söyleyebildiğim kadarıyla false. Olarak başlar undefinedve sonra ayarlanıp ayarlanmadığını söylemek istersiniz true.
ACJ

49

Böyle bir şey deneyebilirsiniz:

var clickEventType=((document.ontouchstart!==null)?'click':'touchstart');
$("#mylink").bind(clickEventType, myClickHandler);

5
Bence sorun, kullanıcının yaptığı şeyden ziyade test cihazı yetenekleri değil mi? Zor olan, aynı zamanda klavyeleri olan dokunmatik cihazları desteklememiz gerektiğidir (böylece her ikisini de kullanıyor olabilirler)
DA.

8
Bu iyi bir fikir değil - fareyi kullanırken dokunmatik ekranlı ve fareli bir kullanıcı için olayı kıracak (dokunmatik ekranlı dizüstü bilgisayarlar oldukça yaygın hale geliyor).
Kristian


Windows 8 her zaman 'touchstart' olayını bağlar çünkü 'ontouchstart' bu işletim sistemi için 'true' değerini döndürür. Bu nedenle, kodunuz yalnızca gerçek dokunmatik ekranlı cihazlarda çalışmayacaksa, muhtemelen en iyi yanıt değildir, ancak bu durumda, kontrole hiç ihtiyacınız yoktur.
Neil Monroe

Dokunmatik ekranlı dizüstü bilgisayarlarda, kullanıcı bu kodu kromda (en azından krom 46) kullanarak hiçbir şeyi tıklayamaz. IE 11 olsa çalışıyor gibi görünüyor.
David Sherret

42

Genellikle bu da işe yarar:

$('#buttonId').on('touchstart click', function(e){
    e.stopPropagation(); e.preventDefault();
    //your code here

});

8
@Jonathan yanlış, daha yeni jQuery sürümleri kullanıyorsanız. Live 1.7 sürümünde kullanımdan kaldırıldı.
Mike Barwick

Ayrıca e.stopPropagation () ile denedim (ve başka bir yerde okudum - benim fikrim değil); e.preventDefault (); ve (benim için) neredeyse çalışıyor ama daha sonra keşfettim ki aslında 20 kez tahmin edildiği gibi ama 1 kez değil, bu yüzden kurşun geçirmez değil. Buraya bakın: stackoverflow.com/questions/25671053/… Bu konudaki yorumlarınız için teşekkür ederiz!
Garavani

@MikeBarwick Lütfen yorumunuzu açıklayabilir veya açıklayan bir bağlantı verebilir misiniz? Şimdiden teşekkür ederim.
Billal Begueradj

22

Sadece olay işlevinin return false;sonuna eklemek on("click touchstart")bu sorunu çözebilir.

$(this).on("click touchstart", function() {
  // Do things
  return false;
});

.On () üzerindeki jQuery dokümanlarından

falseBir olay işleyicisinden döndüğünüzde otomatik olarak event.stopPropagation()ve öğelerini arar event.preventDefault(). falseKısayol olarak işleyici için de bir değer iletilebilir function(){ return false; }.


2
harika çalışıyor, her ikisine de sahip cihazlarda sadece bir kez ateş ediyor - bu benim için en temiz en kötü çözüm gibi görünüyor
Adam Cooper

Benim için en iyi şekilde çalıştı ve aslında mantıklı geldi.
Amir5000

Bunun bir dezavantajı var mı? Neden bu kadar basit bir çözüm yaygın olarak bilinmemektedir?
ESR

11

Benzer bir şey yapmak zorundaydım. İşte benim için çalışanların basitleştirilmiş bir versiyonu. Bir dokunma olayı algılanırsa, tıklama bağlamasını kaldırın.

$thing.on('touchstart click', function(event){
  if (event.type == "touchstart")
    $(this).off('click');

  //your code here
});

Benim durumumda click olayı bir <a>öğeye bağlıydı, bu nedenle tıklama bağlayıcısını kaldırmak ve <a>öğenin varsayılan eylemini engelleyen bir click olayını yeniden bağlamak zorunda kaldım .

$thing.on('touchstart click', function(event){
  if (event.type == "touchstart")
    $(this).off('click').on('click', function(e){ e.preventDefault(); });

  //your code here
});

Keşke bu şekilde çalışsaydı ama olmadı. $ (this) ne düşündüğünü göstermez.
Dave Lowerre

8

Aşağıdaki şekilde başardım.

Tereyağından kıl çeker gibi...

$(this).on('touchstart click', function(e){
  e.preventDefault();
  //do your stuff here
});

4
hem tıklama hem de dokunma başlatan cihazlarda iki kez patlamaz mı?
DA.

8
Üzgünüm, seni tanıdım. Evet, bir dokunuşun touchstart olayı ve tıklama olayı üreteceği haklısınız. Buna hayalet tıklama denir. Google bunun için bir çözüm uyguladı. Düz ileri olmayabilir ama mükemmel çalışıyor. Bağlantı burada. code.google.com/mobile/articles/fast_buttons.html#ghost
Hasanavi

2
önemsiz olabilir ama Kaçırdığınız eparametreyifunction()
ProblemsOfSumit

@Hasanavi bu harika bir düzeltmeydi ancak .on kullanarak daha iyi sonuçlar buldum
Neil

1
Teşekkürler @Neil. Evet .on kullanmak daha iyi bir fikirdir çünkü gelecekteki sürümde kaldırılabilir. Örneğimi bağlama yerine açık olarak değiştirdim.
Hasanavi

5

En iyi uygulamanın şimdi kullanmak olduğuna inanıyorum:

$('#object').on('touchend mouseup', function () { });

touchEnd

Dokunmatik yüzey olaydan bir temas noktası kaldırıldığında, dokunma olayı tetiklenir.

TouchEnd olay olacak değil herhangi bir fare olayları tetikleyebilir.


mouseup

Fare işaretçisi öğenin üzerindeyken fare düğmesi olayı bir öğeye gönderilir ve fare düğmesi serbest bırakılır. Herhangi bir HTML öğesi bu etkinliği alabilir.

Mouseup olay olacak değil herhangi dokunmatik olayları tetikleyebilir.

MİSAL

$('#click').on('mouseup', function () { alert('Event detected'); });
$('#touch').on('touchend', function () { alert('Event detected'); });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1 id="click">Click me</h1>
<h1 id="touch">Touch me</h1>


DÜZENLE (2017)

2017 itibariyle, Chrome ile başlayan ve .on("click")tıklama isteklerinde dokunma etkinliklerinin oluşturduğu gecikmeyi ortadan kaldırarak tıklama etkinliğini hem fare hem de dokunma için daha uyumlu hale getirmeye yönelik adımlar atıyor .

Bu, yalnızca click olayını kullanmaya geri dönmenin ileriye giden en basit çözüm olacağı sonucuna götürür.

Bunun pratik olup olmadığını görmek için henüz çapraz tarayıcı testi yapmadım.


Bu bana umut vaat ediyor gibiydi, bu yüzden onunla bir sürü uğraştım, ama sonuçta mouseup, özellikle geleneksel bir fare yerine bir izleme paneli kullanırken öngörülemeyen sonuçlar buldum .
skybondsor

4

Genellikle varsayılan dokunma ve dokunma (tıklama) api'lerini karıştırmak istemezsiniz. Dokunma dünyasına girdikten sonra sadece dokunmayla ilgili işlevlerle başa çıkmak daha kolaydır. Aşağıda, istediğinizi yapacak bazı sahte kodlar verilmiştir.

Touchmove olayına bağlanır ve konumları izlerseniz, hareketleri ve neyin olmadığını tespit etmek için doTouchLogic işlevine daha fazla öğe ekleyebilirsiniz.

var touchStartTime;
var touchStartLocation;
var touchEndTime;
var touchEndLocation;

$thing.bind('touchstart'), function() {
     var d = new Date();
     touchStartTime = d.getTime();
     touchStartLocation = mouse.location(x,y);
});

$thing.bind('touchend'), function() {
     var d = new Date();
     touchEndTime= d.getTime();
     touchEndLocation= mouse.location(x,y);
     doTouchLogic();
});

function doTouchLogic() {
     var distance = touchEndLocation - touchStartLocation;
     var duration = touchEndTime - touchStartTime;

     if (duration <= 100ms && distance <= 10px) {
          // Person tapped their finger (do click/tap stuff here)
     }
     if (duration > 100ms && distance <= 10px) {
          // Person pressed their finger (not a quick tap)
     }
     if (duration <= 100ms && distance > 10px) {
          // Person flicked their finger
     }
     if (duration > 100ms && distance > 10px) {
          // Person dragged their finger
     }
}

Herhalde sorunun temelini oluşturduğunu düşünüyorum: Her iki modeli de bir kod tabanı ile denemek ve desteklemek mantıklı mı? Sorumu daha fazla senaryo ile güncelleyeceğim.
DA.

1
"Genel olarak varsayılan dokunuşu ve dokunmasızlığı karıştırmak istemezsiniz" bunu kabul ettikten sonra katılıyorum. Sorun şu ki, biz geliştiriciler için bir baş ağrısı olan klavye ile dokunmatik cihazlar yapmaya devam ediyorlar.
DA.

Son js karar dokunuşunun ya da dokunuşunun başlangıcında yapmanın çok daha kolay olacağını kabul ediyorum. Ne kolay bir dünya olurdu! Peki, bu lanet olası cihazların tıklama ve dokunmaya duyarlı olmaları nedir? Onlar yüzünden tüm bu baş ağrılarına sahip olmaya değer mi? Bu kendime sorduğum gelecek mi?
Garavani

Fonksiyonların çoklu tanımlarına sahip olma fikrinden hoşlanmıyorum. Şirketim şu anda bir iPad'in mobil cihaz olarak özel olarak ele alınmadığı ve hala touchend etkinliğine ihtiyacınız olan bir proje üzerinde çalışıyor. Ancak touchend normal masaüstü sürümlerinde çalışmaz. Bu nedenle, bu senaryo için Mottie'nin çözümü mutlak para cezası.
Pete


3

Şey ... Bunların hepsi çok karmaşık.

Modernizriniz varsa, bu beyinsizdir.

ev = Modernizr.touch ? 'touchstart' : 'click';

$('#menu').on(ev, '[href="#open-menu"]', function(){
  //winning
});

2
Bunun ne yaptığını açıklayabilir misiniz? Cihazın dokunmayı destekleyip desteklemediğini kontrol edip etmiyorsa, tıklamayı kullanıp kullanmadığını kontrol ediyorum. Yakalama (ya da en azından , soruyu yazdığım zaman) bazı cihazların her ikisini de desteklemesiydi. Ve bu cihazlarda, tetikleyici dokunma veya tıklamadan gelebileceği için her iki olayı da işlemem gerekiyor.
DA.

2
Biraz daha açıklama öneriyorum.
Aaron Hall

2

Daha iyi bakım için başka bir uygulama. Ancak, bu teknik event.stopPropagation () işlevini de gerçekleştirir. Tıklama 100 ms boyunca tıklanan başka bir öğeye takılmaz.

var clickObject = {
    flag: false,
    isAlreadyClicked: function () {
        var wasClicked = clickObject.flag;
        clickObject.flag = true;
        setTimeout(function () { clickObject.flag = false; }, 100);
        return wasClicked;
    }
};

$("#myButton").bind("click touchstart", function (event) {
   if (!clickObject.isAlreadyClicked()) {
      ...
   }
}

2

Sadece dokümantasyon amaçlı olarak, masaüstünde / mobil çözümde düşünebileceğim en hızlı / en duyarlı tıklama için yaptığım şey:

Ben jQuery'nin yerini ontarayıcı destekleri olayları dokunmatik zaman, touchstart ile tüm tıklama olayları yerini, modifiye biriyle fonksiyonunu.

$.fn.extend({ _on: (function(){ return $.fn.on; })() });
$.fn.extend({
    on: (function(){
        var isTouchSupported = 'ontouchstart' in window || window.DocumentTouch && document instanceof DocumentTouch;
        return function( types, selector, data, fn, one ) {
            if (typeof types == 'string' && isTouchSupported && !(types.match(/touch/gi))) types = types.replace(/click/gi, 'touchstart');
            return this._on( types, selector, data, fn);
        };
    }()),
});

Kullanım, eskisi gibi tam olarak aynı olurdu:

$('#my-button').on('click', function(){ /* ... */ });

Ancak, kullanılabilir olduğunda dokunmatik başlangıç ​​kullanır, olmadığında tıklayın. Herhangi bir gecikmeye gerek yoktur: D


1
Bununla yakalamak, her iki etkileşimi de sağladığınızdan emin olmanız gereken İKİ dokunmatik ve klavyeyi destekleyen cihazlar olacaktır.
DA.

İyi gözlem @DA. Yalnızca tıklama etkinliğini onunla birlikte herhangi bir dokunma etkinliği kullanmıyorsanız değiştirmek için bir kontrol ekledim. Stil her proje için bir çözüm olmayacak, ama eminim ki pek çok kişi için iyi bir seçim olacaktır.
Gerson Goulart

2

Az ontouchstartönce tetiklenip tetiklenmediğini ezberleme fikri buldum . Bu durumda, onu destekleyen ve onclicketkinliği yok saymak isteyen bir cihazdayız. Yana ontouchstarthep tetiklenen edilmelidir önce onclick , bu kullanıyorum:

<script> touchAvailable = false; </script>
<button ontouchstart="touchAvailable=true; myFunction();" onclick="if(!touchAvailable) myFunction();">Button</button>


1
Kullanıcılar aynı sayfa ziyareti sırasında dokunma ve fare kullanabileceğinden, bu snippet ile ilgili sorun olay başına bir kez touchAvailable bayrağını kaydetmesidir. Stackoverflow.com/a/26145343/328272 adresindeki jQuery eklentisi kodunuzla aynı şeyi yapar, ancak bir fare etkinliğini olay temelinde dokunma veya fare ile tetiklenip tetiklenmediğini söyleyebilir. Sadece ie değil. fare işaretçisinden sonra saniyeler (veya dakikalar) tetiklenebilen fare imlecine (fare hareketleriyle fareyle üzerine gelindiğinde genişletilmesi veya dokunma kullanırken tıklanması gereken açılır menüler için idealdir).
lmeurs

2

Böyle deneyebilirsiniz:

var clickEvent = (('ontouchstart' in document.documentElement)?'touchstart':'click');
$("#mylink").on(clickEvent, myClickHandler);

dokunma ve fareyi destekleyen cihazlara ne dersiniz
Walle Cyril

2

Benim durumumda bu mükemmel çalıştı:

jQuery(document).on('mouseup keydown touchend', function (event) {
var eventType = event.type;
if (eventType == 'touchend') {
    jQuery(this).off('mouseup');
}
});

Asıl sorun, bunun yerine fareyle tıklamayı denediğimde, dokunmatik cihazlarda tıklama ve touchend'i aynı anda tetikledi, tıklamayı kullanırsam, bazı işlevler mobil cihazlarda hiç çalışmadı. Tıklama ile ilgili sorun, touchend dahil etkinliğin geri kalanını tetikleyen küresel bir olaydır.


1

Bu benim için çalıştı, mobil her ikisini de dinliyor, bu yüzden dokunma olayı olanı önleyin. masaüstü sadece fare dinle.

 $btnUp.bind('touchstart mousedown',function(e){
     e.preventDefault();

     if (e.type === 'touchstart') {
         return;
     }

     var val = _step( _options.arrowStep );
               _evt('Button', [val, true]);
  });

1

Benim için Mottie tarafından verilen en iyi cevap olmak, sadece kodunu daha yeniden kullanılabilir yapmaya çalışıyorum, bu yüzden bu benim katkısı:

bindBtn ("#loginbutton",loginAction);

function bindBtn(element,action){

var flag = false;
$(element).bind('touchstart click', function(e) {
    e.preventDefault();
    if (!flag) {
        flag = true;
        setTimeout(function() {
            flag = false;
        }, 100);
        // do something
        action();
    }
    return false;
});

0

Ben de bir Android / iPad web uygulaması üzerinde çalışıyorum ve sadece "touchmove" kullanarak bileşenleri taşımak için yeterli görünüyor (touchstart gerek yok). Touchstart'ı devre dışı bırakarak .click (); jQuery'den. Aslında işe yarıyor çünkü touchstart tarafından aşırı yüklenmedi.

Son olarak, binb .live ("touchstart", function (e) {e.stopPropagation ();}); touchstart olayından ilerlemeyi durdurmasını, oturma odasının tetiklenmesi için () tıklamasını istemek.

Benim için çalıştı.


Nasıl devre dışı bırakırsınız touchstart?
punkrockbuddyholly

Ben "olabilir" gibi bir şey yapmak inanıyorum: jQuery ("# ​​my_element"). On ('touchstart', function (e) {e.preventDefault ()});
nembleton

0

Bu sorunu çözmeye çalışırken göz önünde bulundurulması gereken çok şey var. Çoğu çözüm kaydırmayı keser veya hayalet tıklama olaylarını düzgün işlemez.

Tam bir çözüm için bkz. Https://developers.google.com/mobile/articles/fast_buttons

Not: Hayalet tıklama olaylarını her öğe için ayrı ayrı işleyemezsiniz. Gecikmeli bir tıklama ekran konumuna göre tetiklenir, bu nedenle dokunma etkinlikleriniz sayfayı bir şekilde değiştirirse, tıklama etkinliği sayfanın yeni sürümüne gönderilir.


0

Olaylara atamak 'touchstart mousedown'veya 'touchend mouseup'kullanımın istenmeyen yan etkilerinden kaçınmak etkili olabilir click.


0

Bir tıklamanın her zaman bir dokunma olayını takip edeceği gerçeğinden yararlanarak, zaman aşımlarını veya global bayrakları kullanmak zorunda kalmadan "hayalet tıklama" dan kurtulmak için yaptığım şey budur.

$('#buttonId').on('touchstart click', function(event){
    if ($(this).data("already")) {
        $(this).data("already", false);
        return false;
    } else if (event.type == "touchstart") {
        $(this).data("already", true);
    }
    //your code here
});

Temel olarak ontouchstart, bir öğe öğeye her tetiklendiğinde, bir küme işaretlenir ve ardından tıklama geldiğinde kaldırılır (ve yoksayılır).


0

Neden jQuery Olay API'sını kullanmıyorsunuz?

http://learn.jquery.com/events/event-extensions/

Bu basit olayı başarıyla kullandım. Temiz, isimlendirilebilir ve geliştirilebilecek kadar esnek.

var isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent);
var eventType = isMobile ? "touchstart" : "click";

jQuery.event.special.touchclick = {
  bindType: eventType,
  delegateType: eventType
};

1
Kullanıcı aracısı koklama özelliği üzerinden özellik algılamanın kullanılması önerilir.
jinglesthula

Yakalama, hem dokunmayı hem de tıklamayı destekleyen cihazlardır.
DA.

0

JQuery kullanıyorsanız aşağıdakiler benim için oldukça iyi çalıştı:

var callback; // Initialize this to the function which needs to be called

$(target).on("click touchstart", selector, (function (func){
    var timer = 0;
    return function(e){
        if ($.now() - timer < 500) return false;
        timer = $.now();
        func(e);
    }
})(callback));

Diğer çözümler de iyidir, ancak bir döngüde birden çok olayı bağlıyordum ve uygun bir kapatma oluşturmak için kendi kendine arama işlevine ihtiyaç duydum. Ayrıca, bir sonraki tıklama / dokunma başlangıcında çağrılabilmesini istediğim için bağlayıcıyı devre dışı bırakmak istemedim.

Benzer durumdaki birine yardım edebilir!


0

Basit özellikler için dokunmayı tanımanız veya aşağıdaki kodu kullanmam'ı tıklamanız yeterlidir:

var element = $("#element");

element.click(function(e)
{
  if(e.target.ontouchstart !== undefined)
  {
    console.log( "touch" );
    return;
  }
  console.log( "no touch" );
});

Bu, touchstart olayı tanımlanmışsa "dokunma" ve değilse "dokunma" döndürür. Dediğim gibi bu tıklama / musluk olayları için basit bir yaklaşım.


0

Bunu deniyorum ve şimdiye kadar çalışıyor (ama ben sadece Android / Phonegap öylesine uyarı emptor)

  function filterEvent( ob, ev ) {
      if (ev.type == "touchstart") {
          ob.off('click').on('click', function(e){ e.preventDefault(); });
      }
  }
  $('#keypad').on('touchstart click', '.number, .dot', function(event) {
      filterEvent( $('#keypad'), event );
      console.log( event.type );  // debugging only
           ... finish handling touch events...
  }

Her dokunuşta işleyicileri yeniden bağladığımdan hoşlanmıyorum, ancak dokunuşlar olarak kabul edilen her şey çok sık gerçekleşmiyor (bilgisayar zamanında!)

Ben '# tuş takımı' için bir işleyicileri bir TON var, bu yüzden çok fazla kod olmadan sorunla başa çıkmanızı sağlayan basit bir işlevi olması neden bu şekilde gitti.



0

EDIT: Benim eski cevap (bu konudaki cevaplara dayalı) benim için gitmek için bir yol değildi. Bir alt menünün mouse enter veya touch click üzerine genişlemesini ve mouse izni veya başka bir touch click'i daraltmasını istedim. Fare olayları normalde dokunma olaylarından sonra tetiklendiğinden, hem dokunmatik ekranı hem de fare girişini aynı anda destekleyen olay dinleyicileri yazmak biraz zordu.

jQuery eklentisi: Dokunmatik Veya Fare

" Touch Or Mouse " adlı bir jQuery eklentisi yazdım (897 bayt küçültüldü) ve bir olayın dokunmatik ekran veya fare tarafından çağrılıp çağrılmadığını algılayabilir (dokunmatik desteği test etmeden!). Bu, hem dokunmatik ekranın hem de farenin aynı anda desteklenmesini sağlar ve olaylarını tamamen ayırır.

OP kullanabilirsiniz Bu şekilde touchstartya da touchendhızlı tıklama dokunmak yanıt vermek için ve clicktıklamalar için çağrılan tek bir fare tarafından.

gösteri

Birincisi yani. gövde öğesi dokunma olaylarını izleme:

$(document.body).touchOrMouse('init');

Fare, öğelere bağlılığımızı varsayılan şekilde arar ve arayarak $body.touchOrMouse('get', e)olayın bir dokunmatik ekran veya fare tarafından çağrılıp çağrılmadığını öğrenebiliriz.

$('.link').click(function(e) {
  var touchOrMouse = $(document.body).touchOrMouse('get', e);

  if (touchOrMouse === 'touch') {
    // Handle touch click.
  }
  else if (touchOrMouse === 'mouse') {
    // Handle mouse click.
  }
}

Eklentiyi http://jsfiddle.net/lmeurs/uo4069nh adresindeki iş yerinde görün. .

açıklama

  1. Bu eklentinin ie çağrılması gerekir. gövde elemanının izlenmesi touchstartve touchendolaylar, bu şekilde touchendolayın tetikleyici eleman üzerinde (yani bir bağlantı veya düğme) tetiklenmesi gerekmez. Bu iki dokunma olayı arasında bu eklenti, herhangi bir fare olayının dokunarak çağrıldığını düşünür.
  2. Fare olayları ancak sonrasında touchendbaşlatılır, sonra bir fare olayı ghostEventDelay(varsayılan olarak 1000 ms) içinde tetiklenirken touchend, bu eklenti fare olayının dokunarak çağrıldığını düşünür.
  3. Dokunmatik ekran kullanarak bir öğeye tıklandığında, öğe :activedurumu kazanır . mouseleaveEleman yani bu durumu kaybeder sonra olay sadece ateşlenir. başka bir öğeye tıklamak. Bu, mouseenteretkinlik tetiklendikten sonraki saniye (veya dakika!) Olabileceğinden, bu eklenti bir öğenin son mouseenteretkinliğini izler : son mouseenteretkinlik dokunarak çağrıldıysa, aşağıdaki mouseleaveolayın da dokunarak çağrıldığı kabul edilir.

0

İşte bunu yapmanın basit bir yolu:

// A very simple fast click implementation
$thing.on('click touchstart', function(e) {
  if (!$(document).data('trigger')) $(document).data('trigger', e.type);
  if (e.type===$(document).data('trigger')) {
    // Do your stuff here
  }
});

Temel olarak, jQuery'nin kök belgeye bağlı veri nesnesindeki 'trigger' özelliğine tetiklenen ilk olay türünü kaydedersiniz ve yalnızca olay türü 'tetikleyici' değerine eşit olduğunda yürütülür. Dokunmatik cihazlarda, etkinlik zinciri muhtemelen 'touchstart' ve ardından 'click' olur; ancak, "tıklama" işleyicisi yürütülmeyecektir çünkü "tıklama", "tetikleyici" ("dokunmatik başlangıç") içinde kaydedilen ilk etkinlik türüyle eşleşmez.

Varsayım, ve bunun güvenli olduğuna inanıyorum, akıllı telefonunuzun bir dokunmatik cihazdan bir fare cihazına kendiliğinden değişmeyeceği veya 'tetikleme' olay türü yalnızca sayfa yükleme ve "tıklama" ifadesi hiçbir zaman "dokunma başlat" ile eşleşmez.

İşte oynayabileceğiniz bir kod penceresi (bir dokunmatik cihazdaki düğmeye dokunmayı deneyin - tıklama gecikmesi olmamalıdır): http://codepen.io/thdoan/pen/xVVrOZ

Ben de bir seçici dize geçirerek jQuery's torunları filtreleme destekleyen basit bir jQuery eklentisi olarak bu uyguladı:

// A very simple fast click plugin
// Syntax: .fastClick([selector,] handler)
$.fn.fastClick = function(arg1, arg2) {
  var selector, handler;
  switch (typeof arg1) {
    case 'function':
      selector = null;
      handler = arg1;
      break;
    case 'string':
      selector = arg1;
      if (typeof arg2==='function') handler = arg2;
      else return;
      break;
    default:
      return;
  }
  this.on('click touchstart', selector, function(e) {
    if (!$(document).data('trigger')) $(document).data('trigger', e.type);
    if (e.type===$(document).data('trigger')) handler.apply(this, arguments);
  });
};

Kod açıklayıcı: http://codepen.io/thdoan/pen/GZrBdo/


Neden yalnızca değişken kullanmak yerine belgedeki bir data özelliğini kullandınız?
Raphael Schweikert

@RaphaelSchweikert Muhtemelen alışkanlıktan çıktı. Doğru ya da yanlış bir yol yoktur, ancak $.data()birden fazla işlevle erişilebilen ancak küresel kapsama ait olmayan verileri depolamak için kullanmayı seviyorum . Bir artı, onu bir elementte sakladığım için doğal olarak bana daha fazla bağlam sağlıyor.
thdoan

0

Bulduğum en iyi yöntem, touch olayını yazmak ve bu olayın programlı normal click olayını çağırmasını sağlamaktır. Bu şekilde tüm normal tıklama etkinlikleriniz olur ve ardından tüm dokunma etkinlikleri için yalnızca bir etkinlik işleyici eklemeniz gerekir. Dokunmatik yapmak istediğiniz her düğüm için, dokunmatik işleyiciyi çağırmak için "dokunmatik" sınıfını eklemeniz yeterlidir. Jquery ile gerçek bir dokunuş olayı ve yanlış pozitif değil emin olmak için bazı mantık ile böyle çalışır.

$("body").on("touchstart", ".touchable", function() { //make touchable  items fire like a click event
var d1 = new Date();
var n1 = d1.getTime();
setTimeout(function() {
    $(".touchable").on("touchend", function(event) {
        var d2 = new Date();
        var n2 = d2.getTime();
        if (n2 - n1 <= 300) {
            $(event.target).trigger("click"); //dont do the action here just call real click handler
        }
    });
}, 50)}).on("click", "#myelement", function() {
//all the behavior i originally wanted
});
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.