2013-07-15 40 views
8

Tôi đang cố gắng xử lý một lần nhấp nút. "Nút" là div tùy chỉnh cũng có thể chứa trẻ em. Gọi lại nhấp chuột sẽ kích hoạt khi người dùng đã nhấp và thả bên trong phần tử. Nếu người dùng nhấp vào bên trong và sau đó kéo và phát hành bên ngoài, trình xử lý sẽ không kích hoạt. Tôi cần phải làm việc này trên cả máy tính để bàn và thiết bị di động, do đó tôi đang sử dụng các sự kiện mousedown/mouseuptouchstart/touchend.Cách phát hiện sự kiện chạm bên ngoài phần tử

tôi cần phải thay đổi lớp nút từ "ép" thành "bình thường" ngay cả khi các phiên bản sử dụng bên ngoài, vì vậy tôi cần phải thêm một người biết lắng nghe để nắm bắt những sự kiện phát hành trong tài liệu:

var $myElement = $("#myelement"); //This is a div and can also contain children. 

    $myElement.on("mousedown touchstart", function(e){ 

     $(this).addClass("pressed");  

     $(document).on("mouseup touchend", function listener(e){ 
      $myElement.removeClass("pressed"); 

      $(document).off("mouseup touchend", listener); 

      var $target = $(e.target); 
      if ($target.is($myElement) || $target.parents().is($myElement)){   
       //FIXME 
       alert("Inside!"); 

       //do something here 
       return false; 
      } else { 
       //FIXME 
       alert("Outside!"); 

       //let event bubble 
      } 
     }); 

     return false; 
    }); 

Nó hoạt động tốt với các nhấp chuột, nhưng nó không hoạt động như mong đợi với các sự kiện cảm ứng. Tôi đã thử nghiệm điều này trong Chrome dành cho Android và khi nhấn vào phần tử, sau đó kéo ra, "Bên trong!" cảnh báo được hiển thị.

Vấn đề là trong tình trạng này:

if ($target.is($myElement) || $target.parents().is($myElement)){ 

Tôi đang cố gắng để kiểm tra xem sự kiện touchend đã xảy ra trong nút hoặc bất kỳ của những đứa trẻ. Nếu nút không có con, khi nhấp vào nó và sau đó phát hành bên ngoài, phần đầu tiên của mệnh đề OR sẽ chuyển thành true. Nếu nút có con và tôi bấm vào các trẻ em, sau đó phát hành trong bất kỳ phần nào khác của màn hình, phần thứ hai của mệnh đề là đúng sự thật.

Điều gì sai với mã này?

Cảm ơn trước.

CẬP NHẬT
Tôi cũng đã thử nghiệm trong BlackBerry 10 với cùng kết quả. Rõ ràng mục tiêu cho sự kiện touchend là nút (hoặc trẻ em), ngay cả khi tôi đã nhấp vào bên ngoài. Đây có phải là cách nó được cho là hoạt động không?

CẬP NHẬT
Và đây là lý do. Đây là what the W3C docs say about the event:

Mục tiêu của sự kiện này phải Element cùng đã nhận được sự kiện touchstart khi điểm tiếp xúc này đã được đặt trên bề mặt, ngay cả khi các điểm tiếp xúc đã kể từ khi chuyển ngoài khu vực tương tác của các phần tử mục tiêu.

Điều đó không có ý nghĩa với tôi, nhưng dù sao điều này giải thích được vấn đề của tôi. Tôi đã giả định sự kiện touchend sẽ được gọi qua yếu tố mà ngón tay được nhả ra. Có thể phát hiện ra ngón tay bên ngoài bằng cách sử dụng một cách tiếp cận khác không?

CẬP NHẬT
Tôi đã cố gắng lấy tọa độ của touchevent để lấy nguyên tố ở đó bằng cách sử dụng document.elementFromPoint. Vấn đề là sự kiện này không chứa tọa độ (các danh sách changedTouchestouches trống). Tôi đã kiểm tra một cách khó khăn sự kiện trong trình gỡ lỗi và không có cách nào để lấy lại các hợp âm từ nó ngoài sự kiện ban đầu. Sau đó, tôi nghĩ rằng tôi có thể lưu trữ sự kiện touchmove cuối cùng và nhận các coords từ đó, nhưng một lần nữa sự kiện này không có tọa độ riêng! Tại sao trên Trái Đất lại có hai sự kiện này khi chúng vô dụng? Và tôi đã thử nghiệm phương pháp này trong iOS, Android và BB10 với kết quả giống nhau.

Tôi đã từ bỏ. Tôi sẽ gọi lại cuộc gọi ngay cả khi người dùng đã nhấp vào bên ngoài.Tôi không thể tin rằng đó là năm 2013 guys và không có (đơn giản) cách để làm điều này? Tôi có thể sử dụng kéo & thả api nhưng theo this nó không được hỗ trợ trên thiết bị di động (Gotta yêu thích phát triển web di động).

+0

Mặc dù nó không thể giúp bạn trực tiếp, tôi đã đặt cùng một kịch bản VanillaJS thực hiện khá nhiều điều tương tự và đăng một phiên bản đơn giản của mã đó [ở đây] (http://stackoverflow.com/questions/13030210/onclick-event-is-occuring-two-times-in-iphone-hybrid-app/13030622 # 13030622) –

+0

@EliasVanOotegem cảm ơn, tôi đã đọc lướt qua nó, nhưng tôi chưa thể kiểm tra nó. Tôi hiện đang đọc nguồn của một số thư viện bạn đã liên kết. Có lẽ tôi đang cố gắng phát minh lại bánh xe ở đây. –

Trả lời

8

Cuối cùng (gần như) nó hoạt động trong BB10 và Android. Tôi đã để lại một số vấn đề trong cập nhật câu hỏi, vì vậy tổng hợp: mục tiêu sự kiện touchend giống như touchstart và không có tọa độ (nhà thiết kế API vì lý do nào đó đã quyết định "ẩn" chúng trong originalEvent bất động sản :) . Vì vậy, tôi lấy các tọa độ kết thúc chạm từ changedTouches[0].pageXchangedTouches[0].pageY và sau đó lấy yếu tố mà ngón tay được nhả ra bằng cách sử dụng document.elementFromPoint. (Trước khi cho ăn phương thức này với tọa độ sự kiện, bạn phải thêm độ lệch cuộn vào x và y). Sau đó, nếu các yếu tố tại điểm đó là nút (hoặc là một đứa trẻ của nó), tôi xử lý các nhấp chuột.

var $myElement = $("#myelement"); //This is a div and can also contain children. 
    var startEvent = touchDevice() ? "touchstart" : "mousedown"; 
    var releaseEvent = touchDevice() ? "touchend" : "mouseup"; 

    $myElement.on(startEvent, function(e){ 

     $(this).addClass("pressed");  

     $(document).on(releaseEvent, function listener(e){ 
      $myElement.removeClass("pressed"); 

      $(document).off(releaseEvent, listener); 

      var $target = null; 
      if(e.type === "mouseup"){ 
       $target = $(e.target);   
      } else {    
       var x = e.originalEvent.changedTouches[0].pageX - window.pageXOffset; 
       var y = e.originalEvent.changedTouches[0].pageY - window.pageYOffset; 
       var target = document.elementFromPoint(x, y); 

       if(target){ 
        $target = $(target); 
       }   
      } 

      if ($target !== null && ($target.is($myElement) || $target.parents().is($myElement))){  
       //FIXME 
       alert("Inside!"); 

       //callback here 
       return false; 
      } else { 
       //FIXME 
       alert("Outside!"); 
      } 
     }); 

     return false; 
    }); 

Bây giờ tôi đã gặp sự cố mới: bằng cách nào đó, các sự kiện nhấp chuột đang được sao chép. Nhưng điều này xứng đáng là một câu hỏi khác (nếu chưa tồn tại).

+1

Sự cố nhấp chuột trùng lặp là do cảnh báo gỡ lỗi gây ra. Tôi đã thay thế chúng bằng 'console.log' và hiện đang hoạt động như mong đợi. –

+0

Điều này thật kinh khủng! Tôi cảm nhận được nỗi đau của bạn. –

+0

Tọa độ phải nằm trong một đối tượng trong danh sách được gọi là targetTouches là thuộc tính của đối tượng sự kiện, mặc dù tôi đã nghe blackberry có thể là cơn ác mộng về hỗ trợ đặc biệt như vậy? đó. Điều này là cần thiết bởi vì bạn có thể muốn xử lý nhiều lần chạm tại cùng một phần tử gốc có thể tạo ra các sự kiện ở rất gần nhau. Thật lạ lùng nhưng API có ý nghĩa hơn nhiều khi bạn cho rằng nó được thiết kế để xử lý nhiều hơn ngón tay như các vấn đề thay thế chuột và là một thiết kế tốt, IMO. Thư viện truy cập để trừu tượng hóa các nội dung cấp thấp sẽ sớm xuất hiện. –

1

Bạn cần một cách tiếp cận khác nhau và gọn gàng hơn với nhau.

Triển khai onmousemove và ontouchmove cho máy tính để bàn và thiết bị di động tương ứng.

btn_obj.onmousemove = CancelOnClick (this); 

Thực hiện chức năng CancelOnClick để đặt cờ từ được nhấn thành bình thường. Nó giúp bạn tiết kiệm từ tất cả các yếu tố của bạn và các điều kiện dựa trên trẻ em của nó.

Hy vọng điều đó sẽ hữu ích.

+0

'CancelOnClick (this);' sẽ gán giá trị trả về của 'CancelOnClick' cho sự kiện' onmousemove', đó là một ý tưởng khủng khiếp –

+1

Điều này không giải quyết được vấn đề phát hiện việc nhả chuột lên phần tử. vấn đề là tôi cần gọi lại khi cuộc gọi kết thúc, không phải khi nó bắt đầu. –

Các vấn đề liên quan