Làm cách nào để liên kết các sự kiện 'touchstart' và 'click' nhưng không phản hồi cả hai?


198

Tôi đang làm việc trên một trang web di động phải hoạt động trên nhiều thiết bị. Người khiến tôi đau đầu nhất lúc này là BlackBerry.

Chúng tôi cần hỗ trợ cả nhấp chuột trên bàn phím cũng như các sự kiện chạm.

Lý tưởng nhất là tôi chỉ sử dụng:

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

nhưng vấn đề chúng ta gặp phải là một số thiết bị blackberry này có độ trễ rất khó chịu từ lúc chạm đến khi kích hoạt nó.

Biện pháp khắc phục là thay vì sử dụng touchstart:

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

Nhưng làm thế nào để tôi ràng buộc cả hai sự kiện, nhưng chỉ bắn một sự kiện? Tôi vẫn cần sự kiện nhấp cho các thiết bị bàn phím, nhưng tất nhiên, không muốn sự kiện nhấp phát sinh nếu tôi đang sử dụng thiết bị cảm ứng.

Một câu hỏi về phần thưởng: Có cách nào để làm điều này và bổ sung các trình duyệt thậm chí không có sự kiện khởi động không? Trong nghiên cứu này, có vẻ như BlackBerry OS5 không hỗ trợ khởi động, do đó cũng cần phải dựa vào các sự kiện nhấp chuột cho trình duyệt đó.

ĐỊA CHỈ:

Có lẽ một câu hỏi toàn diện hơn là:

Với jQuery, có thể / được đề nghị xử lý cả tương tác chạm và tương tác chuột với cùng một ràng buộc không?

Lý tưởng nhất, câu trả lời là có. Nếu không, tôi có một số tùy chọn:

1) Chúng tôi sử dụng WURFL để lấy thông tin thiết bị để có thể tạo ma trận thiết bị của riêng mình. Tùy thuộc vào thiết bị, chúng tôi sẽ sử dụng touchstart HOẶC nhấp chuột.

2) Phát hiện hỗ trợ cảm ứng trong trình duyệt thông qua JS (Tôi cần thực hiện thêm một số nghiên cứu về điều đó, nhưng có vẻ như điều đó là có thể thực hiện được).

Tuy nhiên, điều đó vẫn để lại một vấn đề: những thiết bị hỗ trợ CẢ HAI thì sao. Một số điện thoại chúng tôi hỗ trợ (cụ thể là Nokias và BlackBerry) có cả màn hình cảm ứng bàn phím. Vì vậy, kiểu đó đưa tôi trở lại vòng tròn đầy đủ cho câu hỏi ban đầu ... có cách nào để cho phép cả hai cùng một lúc không?


2
Tốt hơn hết là bạn nên liên kết với touchstart và touchend và viết logic nhấp chuột của riêng bạn cùng với logic chạm của bạn. Gọi lại nhấp chuột tích hợp như không có kiến ​​thức về chạm.
Justin808

Tôi không chắc là tôi theo dõi, Justin. Tôi vẫn không có cả sự kiện chạm và nhấp vào liên kết với nó chứ?
DA.

@DA - không, bạn sẽ không liên kết với cuộc gọi lại .click (). Tôi sẽ cố gắng viết một câu trả lời trong một số mã sudo. Tôi không có thiết bị cảm ứng tiện dụng để viết mã thật :)
Justin808

À, nhưng để làm rõ, tôi vẫn cần các sự kiện nhấp chuột, vì sẽ có người truy cập trang web này bằng các thiết bị không cảm ứng.
DA.

2
Sử dụng .bind('touchstart mouseup')sẽ giải quyết nó (dựa trên một trong những ý kiến ​​dưới đây)
oriadam

Câu trả lời:


135

Cập nhật : Kiểm tra dự án Polyfill jQuery Con trỏ cho phép bạn liên kết với các sự kiện "con trỏ" thay vì chọn giữa chuột và chạm.


Liên kết với cả hai, nhưng tạo một cờ để chức năng chỉ kích hoạt một lần trên 100ms hoặc lâu hơn.

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

  return false
});

7
hmm ... nó cảm thấy hack, nhưng điều đó có thể làm việc. Điều đáng chú ý là trên một số thiết bị này, nó có độ trễ đáng chú ý ... có lẽ gần một giây ... sẽ gây khó chịu cho những thiết bị khác trên thiết bị nhanh hơn.
DA.

15
Thay vì sử dụng clickthay đổi nó thành mousedown... có lẽ độ trễ dài là sự khác biệt giữa mousedownmouseupđó là cách clickxác định a.
Mottie

7
Đây là giải pháp tôi đã đi với. Cảm ơn! Những gì tôi làm là tôi gắn cờ một mục trên touchendbằng cách áp dụng một lớp touched. Điều này kích hoạt trước khi sự kiện nhấp được gọi. Sau đó tôi thêm một sự kiện nhấp chuột đầu tiên kiểm tra sự tồn tại của lớp đó. Nếu nó ở đó, chúng tôi giả sử các sự kiện chạm được kích hoạt và chúng tôi không làm gì với nhấp chuột ngoài việc xóa tên lớp để 'đặt lại' cho lần tương tác tiếp theo. Nếu lớp không có ở đó, thì chúng tôi giả sử họ đã sử dụng bàn phím để nhấp vào mục đó và kích hoạt chức năng từ đó.
DA.

7
Bạn nên lưu ý rằng hầu hết các trình duyệt điện thoại có độ trễ 300ms trong sự kiện nhấp chuột, vì vậy bạn nên tăng mức độ khó chịu lên ít nhất 300, Xem bài viết này về vấn đề trì hoãn 300ms . Điều này về cơ bản là để kích hoạt chức năng "nhấp đúp để phóng to", đây là một tính năng rất quan trọng trong những ngày đầu của iPhone, khi hầu hết các trang web được thiết kế để xem trên màn hình lớn.
sợ

12
Câu hỏi này đã được xem gần 100 nghìn lần vào thời điểm này. Đây có vẻ như là một trường hợp / vấn đề sử dụng cực kỳ phổ biến. Tuy nhiên, câu trả lời này và những câu hỏi khác về câu hỏi này và tương tự đều có vẻ khó hiểu. Giải pháp google, trong khi suy nghĩ thấu đáo hơn hầu hết, dường như chỉ là một vụ hack mạnh mẽ hơn. Đối với một cái gì đó đơn giản như một trình xử lý nhấp chuột, có vẻ như giải pháp nên đơn giản. Không ai tìm thấy một giải pháp không hack cho vấn đề này?
jinglểula

73

Đây là bản sửa lỗi mà tôi "tạo" và nó lấy ra GhostClick và thực hiện FastClick. Hãy tự mình thử và cho chúng tôi biết nếu nó hiệu quả với bạn.

$(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 Trong JavaScript có một chức năng gọi là TouchClick kết hợp những điều trên.
Matt Parkins

5
Tôi cực kỳ thích phương pháp này trong tất cả các câu trả lời cho câu hỏi này vì đây là một) không kiểm tra khả năng của thiết bị và b) không sử dụng setTimeout. Theo kinh nghiệm của tôi, các giải pháp cho các vấn đề như thế này sử dụng setTimeout có thể hoạt động trong hầu hết các trường hợp nhưng thời gian của các sự kiện khá tùy tiện và cụ thể theo thiết bị.
itmequinn

7
Điều này sẽ không hoạt động vì bằng cách chuyển 'sự kiện' trong hàm ẩn danh, nó trở thành một đối tượng cục bộ trong hàm đó, do đó event.handledsẽ bằng undefinedmỗi khi sự kiện được kích hoạt. Đây là một giải pháp: đặt cờ 'được xử lý' trong chính phần tử đích bằng cách sử dụng jQuery.data().
thdoan

3
Bạn có event.stopPropagation();event.preventDefault();từ sự hiểu biết của tôi (và thử nghiệm) sự kiện chỉ có thể được kích hoạt một lần với điều này. vậy tại sao thậm chí kiểm tra if(event.handled !== true)? Đối với tôi nó không cần thiết hay tôi bỏ lỡ điều gì?
nbar

2
Không nên event.handledkiểm tra giá trị true? Theo như tôi có thể nói là không bao giờ false. Nó bắt đầu như là undefined, và sau đó bạn muốn biết liệu nó đã được đặt thành chưa true.
ACJ

49

Bạn có thể thử một cái gì đó như thế này:

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

5
Tôi nghĩ vấn đề với nó là nó đang thử nghiệm khả năng của thiết bị chứ không phải là những gì người dùng đang làm, phải không? Thách thức là chúng ta cần hỗ trợ các thiết bị cảm ứng cũng có bàn phím (để chúng có thể sử dụng cả hai)
DA.

8
Đây không phải là một ý tưởng hay - sẽ phá vỡ sự kiện cho người dùng có màn hình cảm ứng và chuột khi sử dụng chuột (máy tính xách tay có màn hình cảm ứng đang trở nên khá phổ biến).
Kristian J.

1
Bài viết xuất sắc liên quan đến vấn đề này: hacks.mozilla.org/2013/04/ trên
Luke Melia

Windows 8 sẽ luôn kết nối sự kiện 'touchstart' nếu điều này được sử dụng vì 'ontouchstart' sẽ trả về 'true' cho HĐH này. Vì vậy, có lẽ không phải là câu trả lời tốt nhất trừ khi mã của bạn sẽ chỉ chạy trên các thiết bị màn hình cảm ứng thực sự, nhưng nếu đó là trường hợp, bạn hoàn toàn không cần kiểm tra.
Neil Monroe

Trên máy tính xách tay có màn hình cảm ứng, người dùng sẽ không thể nhấp vào bất cứ thứ gì sử dụng mã này bằng chrome (ít nhất là chrome 46). IE 11 dường như hoạt động mặc dù.
David Sherret

42

Thông thường điều này cũng hoạt động:

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

});

8
@Jonathan sai, nếu bạn đang sử dụng các phiên bản jQuery mới hơn. Live bị phản đối trong phiên bản 1.7.
Mike Barwick

Tôi cũng đã thử (và tôi đọc nó ở nơi khác - không phải ý tưởng của tôi) với e.stopPropagation (); e.preventDefault (); và nó hoạt động (đối với tôi) gần như nhưng tôi đã phát hiện ra rằng trên thực tế nó hoạt động như dự đoán 20 lần nhưng 1 lần thì không, vì vậy nó không chống đạn. Xem tại đây: stackoverflow.com/questions/25671053/ Đánh giá cao ý kiến ​​của bạn về vấn đề đó!
Garavani

@MikeBarwick Bạn có thể vui lòng giải thích bình luận của bạn hoặc đưa ra một liên kết giải thích nó? Cảm ơn bạn trước.
Billal Begueradj

22

Chỉ cần thêm return false;vào cuối on("click touchstart")chức năng sự kiện có thể giải quyết vấn đề này.

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

Từ tài liệu jQuery trên .on ()

Trở về falsetừ một trình xử lý sự kiện sẽ tự động gọi event.stopPropagation()event.preventDefault(). Một falsegiá trị cũng có thể được truyền cho người xử lý như một cách viết tắt cho function(){ return false; }.


2
hoạt động tuyệt vời, chỉ bắn một lần trên các thiết bị có cả hai - đây có vẻ là giải pháp hack ít sạch nhất đối với tôi
Adam Cooper

Làm việc tốt nhất cho tôi và thực sự có ý nghĩa tại sao.
Amir5000

Bất kỳ nhược điểm này? Tại sao một giải pháp đơn giản như vậy không được biết đến rộng rãi?
ESR

10

Tôi đã phải làm một cái gì đó tương tự. Đây là một phiên bản đơn giản hóa của những gì làm việc cho tôi. Nếu một sự kiện chạm được phát hiện, loại bỏ ràng buộc nhấp.

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

  //your code here
});

Trong trường hợp của tôi, sự kiện nhấp được liên kết với một <a>phần tử vì vậy tôi phải xóa liên kết nhấp và khởi động lại một sự kiện nhấp để ngăn hành động mặc định cho <a>phần tử.

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

  //your code here
});

Tôi muốn điều này làm việc như là, nhưng nó không. $ (cái này) không chỉ ra những gì bạn nghĩ nó làm.
Dave Lowerre

8

Tôi đã thành công theo cách sau.

Dễ như ăn bánh...

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

4
Sẽ không bắn hai lần trên các thiết bị đăng ký cả nhấp chuột và chạm?
DA.

8
Xin lỗi, tôi đã cho bạn biết. Có bạn đúng, một liên lạc sẽ tạo ra sự kiện touchstart và nhấp vào sự kiện là tốt. Đây được gọi là ma nhấp chuột. Google đã thực hiện một giải pháp cho điều đó. Có thể không thẳng tiến nhưng hoạt động hoàn hảo. Đây là liên kết. code.google.com/mobile/articles/fast_buttons.html#ghost
Hasanavi

2
có thể không quan trọng nhưng bạn đang thiếu etham số trongfunction()
problemsOfSumit

@Hasanavi đây là một sửa chữa tuyệt vời tuy nhiên tôi đã tìm thấy kết quả tốt hơn bằng cách sử dụng .on
Neil

1
Cảm ơn @Neil. Có sử dụng .on là một ý tưởng tốt hơn vì nó có thể bị xóa trong phiên bản tương lai. Tôi đã thay đổi ví dụ của tôi từ ràng buộc sang trên.
Hasanavi

5

Tôi tin rằng cách tốt nhất bây giờ là sử dụng:

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

cảm ứng

Sự kiện touchend được kích hoạt khi một điểm chạm được xóa khỏi bề mặt cảm ứng.

Sự kiện touchend sẽ không kích hoạt bất kỳ sự kiện chuột nào.


chuột

Sự kiện mouseup được gửi đến một phần tử khi con trỏ chuột ở trên phần tử và nút chuột được giải phóng. Bất kỳ yếu tố HTML nào cũng có thể nhận được sự kiện này.

Sự kiện mouseup sẽ không kích hoạt bất kỳ sự kiện chạm nào.

THÍ DỤ

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


EDIT (2017)

Kể từ năm 2017, các trình duyệt bắt đầu với Chrome và thực hiện các bước để làm cho sự kiện nhấp .on("click")tương thích hơn cho cả chuột và chạm bằng cách loại bỏ độ trễ được tạo bởi các sự kiện nhấn vào yêu cầu nhấp.

Điều này dẫn đến kết luận rằng việc quay trở lại sử dụng chỉ sự kiện nhấp chuột sẽ là giải pháp đơn giản nhất tiến về phía trước.

Tôi chưa thực hiện bất kỳ thử nghiệm trình duyệt chéo nào để xem điều này có thực tế không.


Điều này có vẻ hứa hẹn với tôi, vì vậy tôi đã loay hoay với nó, nhưng cuối cùng tôi thấy mouseupcó kết quả không thể đoán trước, đặc biệt là khi sử dụng trackpad thay vì chuột truyền thống.
skybondsor

4

Nói chung, bạn không muốn trộn api cảm ứng mặc định và không chạm (nhấp). Khi bạn di chuyển vào thế giới cảm ứng, sẽ dễ dàng hơn để đối phó với các chức năng liên quan đến cảm ứng. Dưới đây là một số mã giả sẽ làm những gì bạn muốn nó.

Nếu bạn kết nối trong sự kiện touchmove và theo dõi các vị trí, bạn có thể thêm nhiều mục trong chức năng doTouchLogic để phát hiện cử chỉ và không có gì.

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

Tôi cho rằng đó là mấu chốt của câu hỏi: thậm chí có ý nghĩa gì khi thử và hỗ trợ cả hai mô hình với một cơ sở mã. Tôi sẽ cập nhật câu hỏi của tôi với một số tình huống khác.
DA.

1
"Nói chung, bạn không muốn trộn lẫn cảm ứng mặc định và không chạm" sau khi trải qua điều này, tôi đồng ý. Vấn đề là họ liên tục tạo ra các thiết bị cảm ứng bằng bàn phím, điều này làm đau đầu các nhà phát triển của chúng tôi.
DA.

Tôi đồng ý rằng sẽ bắt đầu dễ dàng hơn nhiều khi bắt đầu chạm quyết định js cuối cùng hoặc không chạm. Thế giới thật dễ dàng! Nhưng điều gì về những thiết bị chết tiệt này nhấp và chạm hợp lý? Có đáng để có tất cả những đau đầu vì chúng? Đây có phải là tương lai tôi tự hỏi mình?
Garavani

Tôi không thích ý tưởng có nhiều định nghĩa về hàm. Công ty của tôi hiện đang làm việc trong một dự án mà iPad không được xử lý đặc biệt như thiết bị di động và bạn vẫn cần sự kiện touchend. Nhưng touchend không hoạt động trên các phiên bản máy tính để bàn thông thường. Vì vậy, giải pháp của @mottie là hoàn toàn tốt cho kịch bản đó.
Pete


3

Chà ... Tất cả những thứ này đều siêu phức tạp.

Nếu bạn có Modernizr, đó là một việc không có trí tuệ.

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

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

2
Bạn có thể giải thích những gì nó làm? Tôi tin rằng nó sẽ kiểm tra xem thiết bị có hỗ trợ cảm ứng hay không và sử dụng nhấp chuột. Điều hấp dẫn là (hoặc ít nhất , khi tôi viết câu hỏi) là một số thiết bị hỗ trợ cả hai. Và trên các thiết bị đó, tôi vẫn cần xử lý cả hai sự kiện, vì trình kích hoạt có thể đến từ một lần chạm hoặc nhấp.
DA.

2
Tôi khuyên bạn nên giải thích thêm một chút.
Aaron Hall

2

Một thực hiện khác để bảo trì tốt hơn. Tuy nhiên, kỹ thuật này cũng sẽ làm event.stopPropagation (). Nhấp chuột không được bắt vào bất kỳ yếu tố nào khác đã nhấp trong 100ms.

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

Chỉ dành cho mục đích tài liệu, đây là những gì tôi đã thực hiện để nhấp nhanh nhất / phản hồi nhanh nhất trên máy tính để bàn / nhấn vào giải pháp di động mà tôi có thể nghĩ ra:

Tôi đã thay thế onchức năng của jQuery bằng một chức năng đã được sửa đổi, bất cứ khi nào trình duyệt hỗ trợ các sự kiện chạm, đã thay thế tất cả các sự kiện nhấp chuột của tôi bằng touchstart.

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

Cách sử dụng sẽ giống hệt như trước đây, như:

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

Nhưng nó sẽ sử dụng touchstart khi có sẵn, nhấp khi không. Không có sự chậm trễ của bất kỳ loại cần thiết: D


1
Điều bắt gặp với điều này sẽ là các thiết bị hỗ trợ CẢ HAI cảm ứng VÀ bàn phím nơi bạn cần đảm bảo bạn có đủ khả năng tương tác.
DA.

Quan sát tốt @DA. Tôi đã thêm một kiểm tra để chỉ thay thế sự kiện nhấp nếu bạn không sử dụng bất kỳ sự kiện chạm nào kết hợp với sự kiện đó. Stil sẽ không phải là một giải pháp cho mọi dự án, nhưng tôi chắc chắn sẽ phù hợp với nhiều người.
Gerson Goulart

2

Tôi chỉ ontouchstartnảy ra ý tưởng để ghi nhớ nếu đã từng được kích hoạt. Trong trường hợp này, chúng tôi đang ở trên một thiết bị hỗ trợ nó và muốn bỏ qua onclicksự kiện này. Vì ontouchstartphải luôn được kích hoạt trước đó onclick , nên tôi đang sử dụng:

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


1
Vì người dùng có thể sử dụng cảm ứng và chuột trong cùng một lần truy cập trang, vấn đề với đoạn mã này là nó đăng ký cờ touchAv Available một lần thay vì mỗi sự kiện. Plugin jQuery từ stackoverflow.com/a/26145343/328272 thực hiện giống như mã của bạn, nhưng có thể cho biết sự kiện chuột cho dù nó được kích hoạt bằng cảm ứng hay chuột trên cơ sở sự kiện. Không chỉ có nghĩa là. khi nhấp, nhưng cũng trên mouseleave có thể được kích hoạt vài giây (hoặc phút) sau mouseenter (lý tưởng cho menu bay ra sẽ mở rộng khi di chuột bằng cử chỉ chuột hoặc nhấp khi sử dụng cảm ứng).
lmeurs 23/12/14

2

Bạn có thể thử như thế này:

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

Còn các thiết bị hỗ trợ cảm ứng và chuột
Walle Cyril

2

Trong trường hợp của tôi, điều này làm việc hoàn hảo:

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

Vấn đề chính là khi thay vào đó tôi đã thử dùng clickup, trên các thiết bị cảm ứng đã kích hoạt nhấp và chạm vào cùng một lúc, nếu tôi sử dụng nhấp tắt, một số chức năng hoàn toàn không hoạt động trên thiết bị di động. Vấn đề với nhấp chuột là một sự kiện toàn cầu kích hoạt phần còn lại của sự kiện bao gồm cả touchend.


1

Điều này làm việc cho tôi, điện thoại di động lắng nghe cả hai, vì vậy hãy ngăn chặn một, đó là sự kiện cảm ứng. máy tính để bàn chỉ nghe chuột.

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

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

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

1

Đối với tôi là câu trả lời hay nhất mà Mottie đưa ra, tôi chỉ đang cố gắng làm cho mã của anh ta có thể tái sử dụng nhiều hơn, vì vậy đây là đóng góp của tôi:

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

Tôi cũng đang làm việc trên một ứng dụng web Android / iPad và dường như chỉ cần sử dụng "touchmove" là đủ để "di chuyển các thành phần" (không cần chạm vào). Bằng cách vô hiệu hóa touchstart, bạn có thể sử dụng .click (); từ jQuery. Nó thực sự hoạt động vì nó không bị quá tải bởi touchstart.

Cuối cùng, bạn có thể binb .live ("touchstart", function (e) {e.stopPropagation ();}); để yêu cầu sự kiện touchstart ngừng lan truyền, phòng khách nhấp () để được kích hoạt.

Nó làm việc cho tôi.


Làm thế nào bạn sẽ vô hiệu hóa touchstart?
punkrockbuddyholly

Tôi tin rằng bạn "có thể" làm một cái gì đó như: jQuery ("# ​​my_element"). On ('touchstart', function (e) {e.preventDefault ()});
nembleton

0

Có rất nhiều điều cần xem xét khi cố gắng giải quyết vấn đề này. Hầu hết các giải pháp đều dừng cuộn hoặc không xử lý các sự kiện nhấp chuột đúng cách.

Để biết giải pháp đầy đủ, hãy xem https://developers.google.com/mobile/articles/fast_buttons

Lưu ý: Bạn không thể xử lý các sự kiện nhấp chuột trên cơ sở từng yếu tố. Một nhấp chuột bị trì hoãn được kích hoạt bởi vị trí màn hình, vì vậy nếu các sự kiện chạm của bạn sửa đổi trang theo một cách nào đó, sự kiện nhấp sẽ được gửi đến phiên bản mới của trang.


0

Nó có thể có hiệu quả để gán cho các sự kiện 'touchstart mousedown'hoặc 'touchend mouseup'để tránh các tác dụng phụ không mong muốn của việc sử dụng click.


0

Lợi dụng thực tế là một nhấp chuột sẽ luôn theo dõi một sự kiện chạm, đây là những gì tôi đã làm để thoát khỏi "nhấp chuột ma" mà không phải sử dụng thời gian chờ hoặc cờ toàn cầu.

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

Về cơ bản bất cứ khi nào một ontouchstartsự kiện kích hoạt phần tử, một cờ một bộ và sau đó được gỡ bỏ (và bỏ qua), khi nhấp chuột đến.


0

Tại sao không sử dụng API sự kiện jQuery?

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

Tôi đã sử dụng sự kiện đơn giản này với thành công. Nó sạch sẽ, dễ nhận biết và đủ linh hoạt để cải thiện.

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
Bạn nên sử dụng tính năng phát hiện qua việc đánh hơi tác nhân người dùng.
jinglểula

Bắt là các thiết bị hỗ trợ cả chạm và nhấp.
DA.

0

Nếu bạn đang sử dụng jQuery, những thứ sau đây hoạt động khá tốt đối với tôi:

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

Các giải pháp khác cũng tốt nhưng tôi đã ràng buộc nhiều sự kiện trong một vòng lặp và cần chức năng tự gọi để tạo ra một bao đóng thích hợp. Ngoài ra, tôi không muốn vô hiệu hóa liên kết vì tôi muốn nó có thể được gọi vào lần nhấp / chạm tiếp theo.

Có thể giúp đỡ ai đó trong tình huống tương tự!


0

Đối với các tính năng đơn giản, chỉ cần nhận ra cảm ứng hoặc nhấp vào Tôi sử dụng mã sau đây:

var element = $("#element");

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

Điều này sẽ trả về "chạm" nếu sự kiện chạm bắt đầu được xác định và "không chạm" nếu không. Giống như tôi đã nói đây là một cách tiếp cận đơn giản cho các sự kiện click / tap chỉ vậy.


0

Tôi đang thử cái này và cho đến nay nó vẫn hoạt động (nhưng tôi chỉ có trên Android / Phonegap vì vậy hãy cẩn thận)

  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...
  }

Tôi không thích thực tế là tôi đang xử lý lại các trình xử lý trên mỗi lần chạm, nhưng tất cả những điều được coi là chạm không xảy ra rất thường xuyên (trong thời gian máy tính!)

Tôi có một TẤN các trình xử lý như '#keypad' vì vậy có một chức năng đơn giản cho phép tôi xử lý vấn đề mà không cần quá nhiều mã là lý do tại sao tôi đi theo cách này.



0

EDIT: Câu trả lời trước đây của tôi (dựa trên câu trả lời trong chủ đề này) không phải là cách phù hợp với tôi. Tôi muốn có một menu phụ để mở rộng khi nhập chuột hoặc chạm vào nhấp chuột và thu gọn khi rời chuột hoặc nhấp chuột cảm ứng khác. Vì các sự kiện chuột thường được kích hoạt sau các sự kiện chạm, nên thật khó để viết trình nghe sự kiện hỗ trợ cả màn hình cảm ứng và nhập chuột cùng một lúc.

Plugin jQuery: Chạm hoặc Chuột

Cuối cùng tôi đã viết một plugin jQuery có tên là " Touch Or Mouse " (897 byte được rút gọn) có thể phát hiện xem một sự kiện được gọi bằng màn hình cảm ứng hay chuột (mà không cần kiểm tra hỗ trợ cảm ứng!). Điều này cho phép hỗ trợ cả màn hình cảm ứng và chuột cùng một lúc và tách biệt hoàn toàn các sự kiện của chúng.

Bằng cách này, OP có thể sử dụng touchstarthoặc touchendphản ứng nhanh với các nhấp chuột chạm và clickcho các nhấp chuột chỉ được gọi bằng chuột.

Trình diễn

Đầu tiên phải làm cho tức là. các yếu tố cơ thể theo dõi các sự kiện chạm:

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

Chuột sự kiện của chúng tôi bị ràng buộc với các yếu tố theo cách mặc định và bằng cách gọi, $body.touchOrMouse('get', e)chúng tôi có thể tìm hiểu xem sự kiện được gọi bằng màn hình cảm ứng hay chuột.

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

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

Xem plugin tại nơi làm việc tại http://jsfiddle.net/lmeurs/uo4069nh .

Giải trình

  1. Plugin này cần phải được gọi là tức là. phần tử cơ thể để theo dõi touchstarttouchendcác sự kiện, theo cách này, touchendsự kiện này không phải được kích hoạt trên phần tử kích hoạt (ví dụ: một liên kết hoặc nút). Giữa hai sự kiện chạm này, plugin này xem xét bất kỳ sự kiện chuột nào được gọi bằng cảm ứng.
  2. Các sự kiện chuột chỉ được kích hoạt sau touchendkhi sự kiện chuột được kích hoạt trong ghostEventDelay(tùy chọn, 1000ms theo mặc định) sau đó touchend, plugin này coi sự kiện chuột sẽ được gọi bằng cảm ứng.
  3. Khi nhấp vào một yếu tố bằng màn hình cảm ứng, yếu tố đó sẽ đạt được :activetrạng thái. Sự mouseleavekiện chỉ được kích hoạt sau khi phần tử mất trạng thái này tức là. nhấp vào yếu tố khác. Vì đây có thể là vài giây (hoặc phút!) Sau khi mouseentersự kiện được kích hoạt, plugin này theo dõi mouseentersự kiện cuối cùng của một yếu tố : nếu mouseentersự kiện cuối cùng được gọi bằng cảm ứng, mouseleavesự kiện sau đây cũng được coi là được gọi bằng cảm ứng.

0

Đây là một cách đơn giản để làm điều đó:

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

Về cơ bản, bạn lưu loại sự kiện đầu tiên được kích hoạt vào thuộc tính 'kích hoạt' trong đối tượng dữ liệu của jQuery được đính kèm với tài liệu gốc và chỉ thực hiện khi loại sự kiện bằng với giá trị trong 'kích hoạt'. Trên các thiết bị cảm ứng, chuỗi sự kiện có thể sẽ là 'chạm vào' theo sau là 'nhấp chuột'; tuy nhiên, trình xử lý 'nhấp chuột' sẽ không được thực thi vì "nhấp chuột" không khớp với loại sự kiện ban đầu được lưu trong 'kích hoạt' ("chạm vào").

Giả định và tôi tin rằng đó là một cách an toàn, đó là điện thoại thông minh của bạn sẽ không tự động thay đổi từ thiết bị cảm ứng sang thiết bị chuột, nếu không, vòi sẽ không đăng ký vì loại sự kiện 'kích hoạt' chỉ được lưu một lần mỗi lần tải trang và "nhấp chuột" sẽ không bao giờ khớp với "chạm".

Đây là một loại tiền mã hóa mà bạn có thể chơi xung quanh (thử nhấn vào nút trên thiết bị cảm ứng - không nên có độ trễ nhấp): http://codepen.io/thdoan/pen/xVVrOZ

Tôi cũng đã triển khai nó như một plugin jQuery đơn giản cũng hỗ trợ lọc hậu duệ của jQuery bằng cách chuyển một chuỗi bộ chọn:

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

Codepen: http://codepen.io/thdoan/pen/GZrBdo/


Tại sao bạn sử dụng một thuộc tính dữ liệu trên tài liệu thay vì chỉ sử dụng một biến?
Raphael Schweikert

@RaphaelSchweikert Có lẽ chỉ là thói quen. Không có cách nào đúng hay sai, nhưng tôi thích sử dụng $.data()để lưu trữ dữ liệu có thể được truy cập bởi nhiều chức năng chưa thuộc phạm vi toàn cầu. Một điểm cộng là vì tôi đang lưu trữ nó trong một yếu tố nên nó tự nhiên cung cấp cho tôi nhiều bối cảnh hơn.
thdoan

0

Phương pháp tốt nhất tôi đã tìm thấy là viết sự kiện chạm và yêu cầu sự kiện đó gọi sự kiện nhấp bình thường theo chương trình. Bằng cách này, bạn có tất cả các sự kiện nhấp bình thường và sau đó bạn chỉ cần thêm một trình xử lý sự kiện cho tất cả các sự kiện chạm. Đối với mọi nút bạn muốn làm cho có thể chạm được, chỉ cần thêm lớp "có thể chạm" vào nó để gọi trình xử lý cảm ứng. Với Jquery, nó hoạt động như vậy với một số logic để đảm bảo rằng đó là một sự kiện chạm thực sự và không phải là một dương tính giả.

$("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
});
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.