Phát hiện trình duyệt không có chuột và chỉ cảm ứng


149

Tôi đang phát triển một ứng dụng web (không phải là trang web có các trang văn bản thú vị) với giao diện rất khác nhau để chạm (ngón tay của bạn che màn hình khi bạn nhấp) và chuột (phụ thuộc nhiều vào xem trước di chuột). Làm cách nào tôi có thể phát hiện ra rằng người dùng của tôi không có chuột để trình bày cho anh ta giao diện phù hợp? Tôi dự định để lại một công tắc cho những người có cả chuột và cảm ứng (như một số máy tính xách tay).

Khả năng sự kiện cảm ứng trong trình duyệt không thực sự có nghĩa là người dùng đang sử dụng thiết bị cảm ứng (ví dụ: Modernizr không cắt nó). Mã trả lời đúng câu hỏi sẽ trả về false nếu thiết bị có chuột, ngược lại. Đối với các thiết bị có chuột và cảm ứng, thiết bị sẽ trả về sai (không chỉ chạm)

Là một lưu ý phụ, giao diện cảm ứng của tôi cũng có thể phù hợp với các thiết bị chỉ sử dụng bàn phím, do đó, việc thiếu chuột tôi đang tìm cách phát hiện càng nhiều.

Để làm cho nhu cầu rõ ràng hơn, đây là API mà tôi đang tìm cách triển khai:

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


Tôi nghĩ bạn cần suy nghĩ lại về thiết kế của mình nếu bạn muốn một ứng dụng có thể áp dụng cho cả máy tính để bàn và thiết bị di động / cảm ứng nhưng có các hành vi khác nhau cho mỗi ứng dụng. Tôi không nghĩ những gì bạn đang thực sự có thể vào thời điểm này, vì một tìm kiếm nhanh trên Google cho "chuột phát hiện javascript" cho thấy một bài đăng hữu ích vừa phải trên quirksmode.org để phát hiện các trạng thái khác nhau của chuột (nhấp chuột, vị trí, v.v.), nhưng kết quả ZERO về việc chuột có thực sự tồn tại hay không.
davethegr8

24
Có lẽ đó là vì Google đã không giúp tôi nên tôi đã hỏi nó ở đây.
nraynaud

2
Bạn đã thử tài liệu mouseenter từ jquery? $ (tài liệu) .mouseenter (chức năng (e) {alert ("chuột");});
Parag Gajjar

4
Sau khi xem xét gần một chục con đường đầy hứa hẹn chỉ để từ chối từng người trong vòng vài phút, câu hỏi này đang thúc đẩy tôi trở thành những người hâm mộ khá lộng lẫy.
Jordan Gray

Câu trả lời:


65

Vấn đề chính là bạn có các lớp thiết bị / trường hợp sử dụng khác nhau sau đây:

  1. Chuột và keyboad (máy tính để bàn)
  2. Chỉ chạm (điện thoại / máy tính bảng)
  3. Chuột, bàn phím và cảm ứng (cảm ứng máy tính xách tay)
  4. Chạm và bàn phím (bàn phím bluetooth trên máy tính bảng)
  5. Chỉ chuột (Tùy chọn người dùng / trình duyệt bị vô hiệu hóa)
  6. Chỉ bàn phím (Vô hiệu hóa người dùng / tùy chọn duyệt)
  7. Chạm và chuột (tức là các sự kiện di chuột từ bút Galaxy Note 2)

Điều tồi tệ hơn là người ta có thể chuyển đổi từ một số các lớp này sang các lớp khác (cắm chuột, kết nối với bàn phím) hoặc người dùng có thể NGHIÊM TRỌNG trên một máy tính xách tay bình thường cho đến khi chúng vươn ra và chạm vào màn hình.

Bạn đã đúng khi cho rằng sự hiện diện của các nhà xây dựng sự kiện trong trình duyệt không phải là một cách tốt để tiến lên (và nó có phần không nhất quán). Ngoài ra, trừ khi bạn đang theo dõi một sự kiện rất cụ thể hoặc chỉ cố gắng loại trừ một vài lớp ở trên, bản thân việc sử dụng các sự kiện không phải là bằng chứng đầy đủ.

Ví dụ: giả sử bạn đã phát hiện ra rằng người dùng đã phát ra một mousemove thực sự (không phải là sai từ các sự kiện chạm, xem http://www.html5rocks.com/en/mobile/touchandmouse/ ).

Rồi sao?

Bạn kích hoạt kiểu di chuột? Bạn thêm nút nào?

Dù bằng cách nào bạn cũng đang tăng thời gian lên kính vì bạn phải chờ một sự kiện diễn ra.

Nhưng sau đó, điều gì sẽ xảy ra khi người dùng quý tộc của bạn quyết định muốn rút chuột ra và chạm hoàn toàn .. bạn có đợi anh ta chạm vào giao diện bị nhồi nhét của bạn không, sau đó thay đổi ngay sau khi anh ta nỗ lực xác định giao diện người dùng hiện đang đông đúc của bạn?

Ở dạng viên đạn, trích dẫn stucox tại https://github.com/Modernizr/Modernizr/issues/869#issuecomment-15264101

  • Chúng tôi muốn phát hiện sự hiện diện của một con chuột
  • Ae có lẽ không thể phát hiện trước khi một sự kiện được bắn
  • Như vậy, những gì chúng tôi phát hiện là nếu một con chuột đã được sử dụng trong phiên này - nó sẽ không ngay lập tức từ tải trang
  • Có lẽ chúng ta cũng không thể phát hiện ra rằng không có chuột - nó sẽ không được xác định cho đến khi đúng (tôi nghĩ điều này có ý nghĩa hơn là đặt nó sai cho đến khi được chứng minh)
  • Và chúng tôi có lẽ không thể phát hiện ra nếu một con chuột bị ngắt kết nối giữa phiên - điều đó sẽ không thể phân biệt được với người dùng chỉ cần từ bỏ con chuột của họ

Một bên: trình duyệt KHÔNG biết khi nào người dùng cắm chuột / kết nối với bàn phím, nhưng không hiển thị nó với JavaScript .. dang!

Điều này sẽ dẫn bạn đến những điều sau đây:

Theo dõi các khả năng hiện tại của một người dùng nhất định là phức tạp, không đáng tin cậy và đáng khen

Ý tưởng về tăng cường tiến bộ áp dụng khá tốt ở đây, mặc dù. Xây dựng trải nghiệm hoạt động trơn tru bất kể bối cảnh của người dùng. Sau đó, đưa ra các giả định dựa trên các tính năng của trình duyệt / truy vấn phương tiện để thêm chức năng sẽ tương đối trong bối cảnh giả định. Sự hiện diện của một con chuột chỉ là một trong vô số cách mà người dùng khác nhau trên các thiết bị khác nhau trải nghiệm trang web của bạn. Tạo một cái gì đó có công với hạt nhân của nó và đừng quá lo lắng về cách mọi người nhấp vào các nút.


3
câu trả lời chính xác. Hy vọng, người dùng luôn có một màn hình! Tôi nghĩ việc xây dựng một giao diện phù hợp với chế độ tương tác hiện tại của người dùng là điều hợp lý. Trên máy tính xách tay cảm ứng, sẽ rất hợp lý khi điều chỉnh ứng dụng (tức là các :hoveryếu tố và những thứ tương tự) khi người dùng chuyển từ chuột sang chạm. Có vẻ như người dùng hiện không sử dụng chuột + cảm ứng cùng một lúc (ý tôi là comoonn giống như có 2 người vợ kết nối với cùng một máy tính hahaha)
Sebastien Lorber

@SebastienLorber - ghét phải chia sẻ nó với bạn nhưng người dùng không nhất thiết phải luôn có màn hình. ( Có thể sử dụng javascript để phát hiện nếu trình đọc màn hình đang chạy trên máy người dùng không? )
ashleedawg

57

Làm thế nào về việc lắng nghe một sự kiện mousemove trên tài liệu. Sau đó cho đến khi bạn nghe thấy sự kiện đó, bạn cho rằng thiết bị chỉ chạm hoặc bàn phím.

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

(Ở đâu listenunlistenủy thác cho addEventListenerhoặc attachEventkhi thích hợp.)

Hy vọng rằng điều này sẽ không dẫn đến quá nhiều trò đùa trực quan, nó sẽ hút nếu bạn cần bố trí lại lớn dựa trên chế độ ...


2
Đó là một ý tưởng tốt, nhưng thật không may, sự chậm trễ trong phản hồi sẽ khiến nó không thể sử dụng được khi giao diện người dùng của ứng dụng phụ thuộc vào việc có sẵn chuột hay không .. Điều này đặc biệt đúng nếu ứng dụng có thể bị tấn công, vì vậy các sự kiện chuột sẽ chỉ đánh vào nó nếu chuột di chuyển qua iframe chính nó ..
Jon Gjengset

7
Điều này có thể hoạt động nếu ứng dụng bắt đầu với màn hình giật gân và nút "tiếp tục". Nếu chuột di chuyển trước sự kiện mousedown đầu tiên thì bạn có chuột. Nó sẽ chỉ thất bại nếu nút được tải trực tiếp dưới chuột và người dùng có một bàn tay rất chắc chắn (thậm chí nên di chuyển 1 pixel).
SpliFF

49
ý tưởng hay, nhưng dường như không hoạt động trong thử nghiệm của chúng tôi . iPad kích hoạt sự kiện này.
Jeff Atwood

3
@JeffAtwood bạn đã làm gì trong trường hợp của bạn?
Michael Haren

2
iPad chắc chắn kích hoạt sự kiện mousemove, ngay trước sự kiện mousedown. Tôi đã thấy rằng số lượng mousedown> 0 và số lượng mousedown == số lượng mousemove là một cách tốt để phát hiện không có chuột. Tôi không thể nhân đôi điều này với một con chuột thật.
Peter Wooster

36

Kể từ năm 2018, có một cách tốt và đáng tin cậy để phát hiện xem trình duyệt có chuột (hoặc thiết bị đầu vào tương tự): Các tính năng tương tác phương tiện CSS4 hiện được hỗ trợ bởi hầu hết mọi trình duyệt hiện đại (trừ IE 11 và các trình duyệt di động đặc biệt).

W3C:

Tính năng phương tiện con trỏ được sử dụng để truy vấn sự hiện diện và độ chính xác của thiết bị trỏ như chuột.

Xem các tùy chọn sau:

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

Các truy vấn phương tiện cũng có thể được sử dụng trong JS:

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

Liên quan:

Tài liệu W3: https://www.w3.org/TR/mediaqueries-4/#mf-interaction

Hỗ trợ trình duyệt: https://caniuse.com/#search=media%20features

Vấn đề tương tự: Phát hiện nếu một thiết bị khách hỗ trợ: di chuột và: trạng thái tiêu điểm


Cá nhân tôi thích câu trả lời này nhưng đến bây giờ (10/19), các truy vấn CSS con trỏ và con trỏ chỉ có sẵn trên ~ 85% thiết bị trên toàn thế giới theo caniuse.com. Chắc chắn không tệ, 95% trở lên là thích hợp hơn. Hy vọng điều này sẽ trở thành tiêu chuẩn trên các thiết bị sớm.
MQuiggGeorgia

1
@MQuiggGeorgia Về cơ bản tôi đồng ý với những lời chỉ trích của bạn về cơ bản, nó chưa được hỗ trợ ở mọi nơi. Still caniuse.com đối với tôi nói rằng nó được hỗ trợ 91,2% ( caniuse.com/#feat=css-media-interaction ). Nhìn gần hơn, nó được hỗ trợ ở mọi nơi trừ IE 11 và các trình duyệt dẹt đặc biệt trên thiết bị di động. Công bằng mà nói, điều này đúng với bất kỳ tính năng hiện đại nào, vì Microsoft đã ngừng triển khai các tính năng IE từ lâu. Đối với IE 11, bạn có thể sử dụng dự phòng từ các câu trả lời khác tại đây.
Blackbam

23

Câu trả lời của @ Wyatt rất hay và cho chúng ta nhiều suy nghĩ.

Trong trường hợp của tôi, tôi đã chọn lắng nghe tương tác đầu tiên, để chỉ sau đó thiết lập một hành vi. Vì vậy, ngay cả khi người dùng có chuột, tôi sẽ coi là thiết bị cảm ứng nếu lần tương tác đầu tiên là một lần chạm.

Xem xét thứ tự nhất định trong đó các sự kiện được xử lý :

  1. bắt đầu
  2. cảm ứng
  3. cảm ứng
  4. Di chuột lên trên
  5. bẫy chuột
  6. Di chuột xuống
  7. chuột
  8. nhấp chuột

Chúng ta có thể giả định rằng nếu sự kiện chuột được kích hoạt trước khi chạm, thì đó là sự kiện chuột thực sự chứ không phải sự kiện mô phỏng. Ví dụ (sử dụng jQuery):

$(document).ready(function() {
    var $body = $('body');
    var detectMouse = function(e){
        if (e.type === 'mousedown') {
            alert('Mouse interaction!');
        }
        else if (e.type === 'touchstart') {
            alert('Touch interaction!');
        }
        // remove event bindings, so it only runs once
        $body.off('mousedown touchstart', detectMouse);
    }
    // attach both events to body
    $body.on('mousedown touchstart', detectMouse);
});

Điều đó làm việc cho tôi


Không hoạt động với tôi, Ipad Safari (IOS8.3) cũng phát hiện một con chuột với đoạn trích này
netzaffin

3
@netzaffin. Cảm ơn phản hồi, tôi thấy nó phù hợp hơn khi sử dụng mousedown thay vì mouseover. Bạn có thể xem qua câu đố này từ iOS của bạn và cho tôi biết kết quả không? Chúc mừng jsfiddle.net/bkwb0qen/15/embedded/result
Hugo Silva

1
Nếu bạn có màn hình cảm ứng với chuột, chỉ có phương thức nhập được sử dụng trước sẽ được phát hiện.
0xcaff

11

Chỉ có thể phát hiện nếu trình duyệt có khả năng cảm ứng . Không có cách nào để biết nó thực sự có màn hình cảm ứng hay chuột được kết nối.

Người ta có thể ưu tiên sử dụng mặc dù bằng cách nghe sự kiện chạm thay vì sự kiện chuột nếu phát hiện thấy khả năng cảm ứng.

Để phát hiện khả năng cảm ứng trên nhiều trình duyệt:

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

Sau đó, người ta có thể sử dụng điều này để kiểm tra:

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

hoặc chọn sự kiện nào để nghe, một trong hai:

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

hoặc sử dụng các phương pháp riêng biệt cho cảm ứng so với không chạm:

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
}

Đối với chuột, người ta chỉ có thể phát hiện xem chuột có đang được sử dụng không, có tồn tại hay không. Người ta có thể thiết lập một cờ toàn cầu để chỉ ra rằng chuột đã được phát hiện bằng cách sử dụng (tương tự như câu trả lời hiện có, nhưng đơn giản hóa một chút):

var hasMouse = false;

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

(không thể bao gồm mouseuphoặc mousedownvì những sự kiện này cũng có thể được kích hoạt bằng cảm ứng)

Các trình duyệt hạn chế quyền truy cập vào các API hệ thống cấp thấp cần thiết để có thể phát hiện các tính năng như khả năng phần cứng của hệ thống mà nó đang được sử dụng.

Có khả năng có thể viết một plugin / tiện ích mở rộng để truy cập những thứ này nhưng thông qua JavaScript và DOM, việc phát hiện như vậy bị hạn chế cho mục đích này và người ta sẽ phải viết một plugin dành riêng cho các nền tảng HĐH khác nhau.

Vì vậy, trong kết luận: phát hiện như vậy chỉ có thể được ước tính bằng một "dự đoán tốt".


8

Khi Media Queries Cấp 4 có sẵn trong trình duyệt, chúng tôi sẽ có thể sử dụng truy vấn "con trỏ" và "di chuột" để phát hiện thiết bị bằng chuột.

Nếu chúng tôi thực sự muốn truyền đạt thông tin đó sang Javascript, chúng tôi có thể sử dụng truy vấn CSS để đặt các kiểu cụ thể theo loại thiết bị, sau đó sử dụng getComputedStyle trong Javascript để đọc kiểu đó và lấy ra loại thiết bị gốc từ nó.

Nhưng một con chuột có thể được kết nối hoặc rút phích cắm bất cứ lúc nào và người dùng có thể muốn chuyển đổi giữa cảm ứng và chuột. Vì vậy, chúng tôi có thể cần phát hiện thay đổi này và đề nghị thay đổi giao diện hoặc thực hiện tự động.


1
Cụ thể, any-pointerany-hover sẽ cho phép bạn điều tra tất cả các khả năng của thiết bị. Rất vui được xem qua cách chúng ta có thể giải quyết vấn đề này trong tương lai! :)
Jordan Gray

2
window.matchMedia ("(bất kỳ con trỏ: thô)"). khớp === đúng không?
4esn0k

7

Vì dù sao bạn cũng dự định cung cấp một cách để chuyển đổi giữa các giao diện, nên có thể chỉ cần yêu cầu người dùng nhấp vào liên kết hoặc nút để "nhập" phiên bản chính xác của ứng dụng? Sau đó, bạn có thể nhớ sở thích của họ cho các chuyến thăm trong tương lai. Nó không phải là công nghệ cao, nhưng nó đáng tin cậy 100% :-)


2
Đây thực sự là một gợi ý khá hay, nhưng nó sẽ trì hoãn thời gian trước khi người dùng đến giao diện thực. Ngoài ra, tôi sẽ phải cung cấp cách chuyển đổi sau lựa chọn ban đầu. Kết thúc công việc nhiều hơn là chỉ đơn giản là nó có thể được phát hiện ..
Jon Gjengset

1
Yêu cầu người dùng rõ ràng là cách tốt nhất - nếu không phải lúc nào cũng dễ dàng - Và cung cấp cho bạn một nơi thuận tiện để đưa ra các thông báo nâng cấp và những gì không. Tôi nghĩ bạn đang nghĩ quá nhiều về "vấn đề" ..
T4NK3R

4

@SamuelRossille Không có trình duyệt mà tôi biết về việc phơi bày sự tồn tại của (hoặc thiếu nó) một con chuột, thật không may.

Vì vậy, với điều đó đã được nói, chúng ta chỉ cần cố gắng và làm tốt nhất có thể với tùy chọn ... sự kiện hiện có. Tôi biết đó không chính xác là những gì bạn đang tìm kiếm ... đồng ý rằng nó hiện không còn lý tưởng.

Chúng tôi có thể làm hết sức mình để tìm hiểu xem người dùng đang sử dụng chuột hay chạm vào bất kỳ thời điểm nào. Đây là một ví dụ nhanh và bẩn khi sử dụng jQuery & Knockout:

//namespace
window.ns = {};

// for starters, we'll briefly assume if touch exists, they are using it - default behavior
ns.usingTouch = ko.observable(Modernizr.touch); //using Modernizr here for brevity.  Substitute any touch detection method you desire

// now, let's sort out the mouse
ns.usingMouse = ko.computed(function () {
    //touch
    if (ns.usingTouch()) {
        //first, kill the base mousemove event
        //I really wish browsers would stop trying to handle this within touch events in the first place
        window.document.body.addEventListener('mousemove', function (e) {
            e.preventDefault();
            e.stopImmediatePropagation();
        }, true);

        //remove mouse class from body
        $('body').removeClass("mouse");

        //switch off touch listener
        $(document).off(".ns-touch");

        // switch on a mouse listener
        $(document).on('mousemove.ns-mouse', function (e) {
            if (Math.abs(window.lastX - e.clientX) > 0 || window.lastY !== e.clientY) {
                ns.usingTouch(false);  //this will trigger re-evaluation of ns.usingMouse() and result in ns.usingMouse() === true
            }
        });

        return false;
    }
    //mouse
    else {
        //add mouse class to body for styling
        $('body').addClass("mouse");

        //switch off mouse listener
        $(document).off(".ns-mouse");

        //switch on a touch listener
        $(document).on('touchstart.ns-touch', function () { ns.usingTouch(true) });

        return true;
    }
});

//tests:
//ns.usingMouse()
//$('body').hasClass('mouse');

Bây giờ bạn có thể liên kết / đăng ký để sử dụngMouse () & usingTouch () và / hoặc tạo kiểu giao diện của bạn với body.mouse lớp . Giao diện sẽ chuyển đổi qua lại ngay khi phát hiện con trỏ chuột và khởi động.

Hy vọng chúng tôi sẽ sớm có một số tùy chọn tốt hơn từ các nhà cung cấp trình duyệt.


2

Tera-WURFL có thể cho bạn biết khả năng của thiết bị đang truy cập trang web của bạn bằng cách so sánh chữ ký trình duyệt với cơ sở dữ liệu của nó. Hãy nhìn nó, nó miễn phí!


1
Điều này sẽ không hoạt động đối với các thiết bị có thể có hoặc không có màn hình cảm ứng và chuột. Chẳng hạn, máy tính Windows để bàn có thể được kết nối với màn hình cảm ứng, nhưng thường sẽ có chuột, trong khi máy tính bảng cũng có thể chạy Windows, nhưng có thể không có chuột được kết nối ..
Jon Gjengset

@Jonhoo Chỉ cần giả sử rằng các hệ điều hành Desktop có gắn chuột. Rốt cuộc, họ phải hỗ trợ một loạt các phần mềm không được phát triển với màn hình cảm ứng.
Gigi

1
Còn máy tính bảng chạy Windows 8 đơn giản thì sao? Hay Linux? Hay máy tính xách tay chạy Android?
Jon Gjengset

2
@Jonhoo Rõ ràng cách tiếp cận này ít hơn tối ưu, nhưng không có cách di động nào để biết điều đó (chưa). Nếu một người đang chạy một máy tính xách tay với Android, chỉ cần giả sử nó có khả năng cảm ứng. Nếu một người đang chạy máy tính bảng Windows8, chỉ cần giả sử rằng nó có khả năng chuột (HĐH phải giả lập chuột cho các chương trình không chạm).
Gigi

Điều này bây giờ đã lỗi thời đến mức nó không còn phù hợp nữa.
Kỹ sư

2

Tại sao bạn không phát hiện nếu nó có khả năng cảm nhận chạm và / hoặc phản ứng với chuyển động của chuột?

// 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
Bởi vì một số trình duyệt (ví dụ IE9) báo cáo rằng hàm tồn tại ngay cả khi nó sẽ không bao giờ được kích hoạt. Tôi tin rằng đây cũng là hành vi "đúng".
Jon Gjengset

Tại sao bạn sẽ sử dụng một chức năng? chỉ has_touch = 'ontouchstart' in windowlà đủ, và vân vân.
vsync

Chà, ít nhất nó cũng hoạt động trên Chrome 47 cho OS X. Báo cáo không bắt đầu.
phreakhead

2

Điều này làm việc cho tôi trong một tình huống tương tự. Về cơ bản, giả sử người dùng không có chuột cho đến khi bạn thấy một loạt các mousemove liên tiếp, mà không can thiệp vào bẫy chuột hoặc chuột. Không thanh lịch, nhưng nó hoạt động.

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

Hãy xem modenizr một trong những tính năng của nó là cảm ứng

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

Mặc dù tôi chưa kiểm tra đầy đủ nhưng có vẻ như nó hoạt động rất tốt

Ngoài ra, điều này được liên kết từ trang Modernizr http://www.html5rocks.com/en/mobile/touchandmouse/


Điều này cố gắng phát hiện khả năng cảm ứng, không phải là chỉ có cảm ứng và không có khả năng chuột. Câu hỏi này về cơ bản khác với phát hiện cảm ứng.
Jimbo Jonny

0

Như những người khác đã chỉ ra, chắc chắn phát hiện xem họ có chuột hay không là không đáng tin cậy. Điều này có thể dễ dàng thay đổi, tùy thuộc vào thiết bị. Đó chắc chắn là điều bạn không thể làm một cách đáng tin cậy với boolean đúng hoặc sai, ít nhất là trên thang đo tài liệu.

Sự kiện cảm ứng và sự kiện chuột là độc quyền. Vì vậy, điều này có thể giúp phần nào thực hiện các hành động khác nhau. Vấn đề là các sự kiện chạm gần với sự kiện chuột lên / xuống / di chuyển và cũng kích hoạt sự kiện nhấp chuột.

Từ câu hỏi của bạn, bạn nói rằng bạn muốn có một di chuột để xem trước. Ngoài ra tôi không biết bất kỳ chi tiết cụ thể nào khác về giao diện của bạn. Tôi đang giả sử rằng với việc thiếu chuột, bạn muốn nhấn để xem trước, trong khi nhấp chuột thực hiện một hành động khác vì xem trước di chuột.

Nếu đó là trường hợp bạn có thể sử dụng một cách tiếp cận lười biếng để phát hiện:

Một sự kiện onclick sẽ luôn được bắt đầu bằng một sự kiện onmouseover với một con chuột. Vì vậy, hãy lưu ý rằng chuột nằm trên phần tử đã được nhấp.

Bạn có thể làm điều này với một sự kiện onmousemove trên toàn tài liệu. Bạn có thể sử dụng event.targetđể ghi lại phần tử mà chuột đang cư trú. Sau đó, bên trong các sự kiện onclick của bạn, bạn có thể kiểm tra xem liệu con chuột có thực sự vượt qua phần tử được nhấp hay không (hoặc con của phần tử).

Từ đó, bạn có thể chọn dựa vào sự kiện nhấp cho cả hai và thực hiện hành động A hoặc B tùy thuộc vào kết quả. Hành động B có thể không là gì nếu một số thiết bị cảm ứng không phát ra sự kiện nhấp chuột (thay vào đó bạn sẽ phải dựa vào các sự kiện ontouch *).


0

Tôi không nghĩ có thể xác định thiết bị chỉ cảm ứng (theo hiểu biết của tôi về khóa học). Vấn đề chính là tất cả các sự kiện chuột và bàn phím cũng được kích hoạt bởi các thiết bị cảm ứng. Xem ví dụ sau, cả hai cảnh báo đều trả về true cho thiết bị cảm ứng.

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 ipad trả lại truecho'onmousedown' in window
vsync

0

Ý tưởng tốt nhất theo ý kiến ​​của tôi là mousemovengười nghe (hiện đang là câu trả lời hàng đầu). Tôi tin rằng phương pháp này cần phải được điều chỉnh một chút. Đúng là các trình duyệt dựa trên cảm ứng mô phỏng ngay cả sự kiện mousemove, như bạn có thể thấy trong cuộc thảo luận về iOS này , vì vậy chúng ta nên cẩn thận một chút.

Điều hợp lý là các trình duyệt dựa trên cảm ứng sẽ chỉ mô phỏng sự kiện này khi người dùng chạm vào màn hình (ngón tay của người dùng không hoạt động). Điều này có nghĩa là chúng ta nên thêm một bài kiểm tra trong trình xử lý mousemove của mình để xem nút chuột nào bị hỏng (nếu có) trong sự kiện. Nếu không có nút chuột nào bị hỏng, chúng ta có thể giả sử một con chuột thật có mặt một cách an toàn. Nếu một nút chuột bị hỏng, thử nghiệm vẫn không có kết quả.

Vì vậy, làm thế nào điều này sẽ được thực hiện? Câu hỏi này cho thấy phương pháp đáng tin cậy nhất để kiểm tra nút chuột nào bị hỏng trong một mousemove là thực sự lắng nghe 3 sự kiện ở cấp độ tài liệu: mousemove, mousedown và mouseup. Việc lên và xuống sẽ chỉ thiết lập một cờ boolean toàn cầu. Việc di chuyển sẽ thực hiện kiểm tra. Nếu bạn có một động thái và boolean là sai, chúng ta có thể giả sử có một con chuột. Xem câu hỏi cho các ví dụ mã chính xác.

Một nhận xét cuối cùng .. Thử nghiệm này không lý tưởng vì không thể thực hiện trong thời gian tải. Do đó, tôi sẽ sử dụng phương pháp tăng cường lũy ​​tiến như đề xuất trước đây. Theo mặc định, hiển thị một phiên bản không hỗ trợ giao diện di chuột dành riêng cho chuột. Nếu một con chuột được phát hiện, kích hoạt chế độ này trong thời gian chạy bằng cách sử dụng JS. Điều này sẽ xuất hiện liền mạch nhất có thể cho người dùng.

Để hỗ trợ các thay đổi trong cấu hình của người dùng (tức là chuột đã bị ngắt kết nối), bạn có thể kiểm tra lại định kỳ. Mặc dù tôi tin rằng sẽ tốt hơn trong trường hợp này là chỉ cần thông báo cho người dùng về 2 chế độ và cho phép người dùng tự chuyển đổi giữa chúng (giống như lựa chọn trên thiết bị di động / máy tính để bàn luôn có thể đảo ngược).


Cảm ơn vì đã có những gợi ý giải quyết tốt ... Tôi nghĩ rằng vấn đề chính không được giải quyết tôi sẽ phải dùng đến một trong những điều này
Samuel Rossille

Thật không may mousemove được kích hoạt khi nhấp vào ipad. Chỉ được thử nghiệm với giả lập. Đối với hasMouse () Tôi đã sử dụng if (! ('Ontouchstart' trong cửa sổ)) trả về true; nhưng không hoạt động cho máy tính xách tay hỗ trợ cảm ứng.
Chris Gunawardena

@Chris G - iPad hell ... (đập đầu tôi vào tường)
vsync

0

Chạy một số thử nghiệm trên nhiều PC và điện thoại Linux, iPhone, Android và tab khác nhau. Điều kỳ lạ là không có giải pháp chống đạn dễ dàng. Vấn đề phát sinh khi một số có Touch và không có chuột vẫn hiển thị các sự kiện Touch và Mouse cho ứng dụng. Vì muốn hỗ trợ các trường hợp chỉ sử dụng chuột và cảm ứng, muốn xử lý cả hai, nhưng điều này gây ra sự xuất hiện kép của các tương tác người dùng. Nếu có thể biết chuột không có trên thiết bị, thì có thể biết để bỏ qua các sự kiện chuột giả / chèn. Đã thử cài đặt cờ nếu MouseMove gặp phải, nhưng một số trình duyệt ném MouseMove giả cũng như MouseUp và MouseDown. Đã thử kiểm tra dấu thời gian nhưng cho rằng điều này là quá rủi ro. Điểm mấu chốt: Tôi thấy các trình duyệt đã tạo các sự kiện chuột giả luôn chèn một MouseMove duy nhất ngay trước MouseDown được chèn. Trong 99,99% trường hợp của tôi, khi chạy trên hệ thống có chuột thật, có nhiều sự kiện MouseMove liên tiếp - ít nhất là hai sự kiện. Vì vậy, hãy theo dõi xem hệ thống có gặp hai sự kiện MouseMove liên tiếp hay không và tuyên bố không có chuột nếu điều kiện này không bao giờ được đáp ứng. Điều này có lẽ quá đơn giản, nhưng nó hoạt động trên tất cả các thiết lập thử nghiệm của tôi. Hãy nghĩ rằng tôi sẽ gắn bó với nó cho đến khi tôi tìm thấy một giải pháp tốt hơn. - Jim W


0

Một giải pháp đơn giản trong jQuery để phát hiện việc sử dụng chuột, giải quyết vấn đề trong đó các thiết bị di động cũng kích hoạt sự kiện 'mousemove'. Chỉ cần thêm một trình nghe touchstart để loại bỏ trình nghe mousemove, để nó không bị kích hoạt khi chạm vào.

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

Tất nhiên, thiết bị vẫn có thể chạm và chuột, nhưng ở trên sẽ đảm bảo rằng chuột thật đã được sử dụng.


0

Chỉ cần tìm một giải pháp mà tôi nghĩ là khá thanh lịch.

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

Tôi gặp vấn đề tương tự, trong đó một lần chạm cũng được đăng ký dưới dạng một lần nhấp. Sau khi tôi đọc qua các bình luận của các câu trả lời được bình chọn hàng đầu, tôi đã đưa ra giải pháp của riêng mình:

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

Vấn đề duy nhất tôi tìm thấy là, bạn phải có khả năng cuộn, để phát hiện đúng một sự kiện chạm. một tab duy nhất (chạm) có thể gây ra vấn đề.


0

Tôi đã dành hàng giờ để tìm ra vấn đề này cho ứng dụng Phonegap của mình và tôi đã nghĩ ra cách hack này. Nó tạo ra một cảnh báo giao diện điều khiển nếu sự kiện được kích hoạt là một sự kiện "thụ động", có nghĩa là nó không thực hiện bất kỳ thay đổi nào, nhưng nó hoạt động! Tôi sẽ quan tâm đến bất kỳ ý tưởng để cải thiện hoặc một phương pháp tốt hơn. Nhưng điều này cho phép tôi sử dụng $ .touch () một cách hiệu quả.

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

vấn đề chính tôi thấy ở đây là hầu hết các thiết bị cảm ứng đều kích hoạt sự kiện chuột cùng với cảm ứng lõi (touchstart -> mousedown, touchmove -> mousemove, v.v.). Đối với những người chỉ sử dụng bàn phím, cuối cùng đối với những người hiện đại, họ có một trình duyệt chung để bạn thậm chí không thể phát hiện sự hiện diện của lớp MouseEvent.

Theo tôi, giải pháp ít đau đớn hơn là hiển thị menu khi khởi chạy (với quản lý 'alt' chỉ dành cho người dùng bàn phím) và có thể lưu trữ lựa chọn với localStorage / cookies / serveride hoặc cách khác để giữ cùng lựa chọn tiếp theo thời gian khách đến


-4

Tôi thực sự khuyên bạn nên chống lại phương pháp này. Xem xét màn hình cảm ứng, thiết bị có kích thước máy tính để bàn và bạn có một bộ vấn đề khác để giải quyết.

Vui lòng làm cho ứng dụng của bạn có thể sử dụng mà không cần chuột (tức là không có bản xem trước di chuột).


1
Đó chính xác là những gì tôi đang cố gắng làm. Tôi đang cố gắng tạo một giao diện sẽ hoạt động theo cách tốt nhất có thể trên cả hai máy tính bảng (không có chuột) và với chuột, nhưng những giao diện đó nhất thiết phải rất khác nhau.
Jon Gjengset

Tôi đồng ý với broady. Bạn tốt nhất bằng cách sử dụng phát hiện thiết bị (như DeviceAtlas) và chọn giao diện được cung cấp khi tải.
Teemu Ikonen

-4

Muốn giới thiệu một kịch bản giúp tôi:

Tôi đã đọc và thử mọi thứ được đề xuất, mà không có kết quả đầy đủ.

Sau đó, tôi đã điều tra thêm và tìm thấy mã này - device.js

Tôi đang sử dụng điều này trong trang web của khách hàng, để phát hiện sự tồn tại của chuột:
( <html>nên có desktoplớp) và nó có vẻ khá tốt, và để được touchhỗ trợ, tôi chỉ cần kiểm tra thường xuyên 'ontouchend' in documentvà sử dụng thông tin từ cả hai phát hiện để giả định một điều cụ thể tôi cần.


Điều đó tương đương với việc đánh hơi UA, được nêu ra nhiều lần trong chủ đề này rồi. Nó không giải quyết trường hợp thiết bị có chuột VÀ chạm như Windows 8, và nó chắc chắn không phải là bằng chứng trong tương lai.
Hugo Silva

Tôi sử dụng nó để giải quyết trường hợp CHÍNH XÁC này mà bạn đã đề cập trong ứng dụng của khách hàng và nó hoạt động tốt. nó là bằng chứng trong tương lai, bởi vì nó được duy trì bởi nhà phát triển của nó.
vsync

2
Trường hợp tôi đã đề cập (máy tính xách tay hỗ trợ cảm ứng) sẽ được tập lệnh của bạn xác định là "Máy tính để bàn", mặc dù tôi không thể sử dụng chuột. "Đó là bằng chứng trong tương lai, bởi vì nó được duy trì bởi nhà phát triển của nó" - Tôi nghĩ rằng bạn đã hoàn toàn bỏ lỡ quan điểm "bằng chứng trong tương lai" ở đây. Và nếu bạn đã đọc và thử mọi thứ như bạn đã nêu, bạn sẽ nhận thấy rằng câu trả lời của Gigi đã gợi ý UA đánh hơi.
Hugo Silva

-7

Nói chung là một ý tưởng tốt hơn để phát hiện nếu chức năng di chuột được hỗ trợ thay vì phát hiện loại hệ điều hành / trình duyệt. Bạn có thể làm điều đó đơn giản bằng cách sau:

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

Hãy chắc chắn rằng bạn không làm như sau:

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

Cái sau thực sự sẽ gọi phương thức, thay vì kiểm tra sự tồn tại của nó.

Bạn có thể đọc thêm tại đây: http://www.quirksmode.org/js/support.html


2
Tôi thực sự không biết phải lấy gì từ bài đăng của bạn, nhưng nếu ('onmouseover' trong $ ('body') [0]) alert ('onmouseover'); cũng hiển thị một tin nhắn trong iPhone
nraynaud

1
Điều này chỉ kiểm tra nếu chức năng di chuột được xác định, nó sẽ có trên hầu hết các trình duyệt. Nó không phát hiện nếu một con chuột thực sự có mặt.
Jon Gjengset
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.