브라우저에 마우스가없고 터치 전용임을 감지


149

터치 (손가락을 클릭하면 화면이 숨겨 짐)와 마우스 (호버 미리보기에 크게 의존)와 매우 다른 인터페이스를 가진 웹 응용 프로그램 (흥미로운 텍스트 페이지가있는 웹 사이트가 아님)을 개발 중입니다. 사용자에게 올바른 인터페이스를 제공 할 마우스가 없는지 어떻게 알 수 있습니까? 마우스와 터치가있는 사람 (예 : 일부 노트북)을위한 스위치를 남겨 둘 계획입니다.

브라우저의 터치 이벤트 기능이 실제로 사용자가 터치 장치를 사용하고 있다는 것을 의미하지는 않습니다 (예 : Modernizr가 자르지 않음). 장치에 마우스가 있으면 질문에 올바르게 대답하는 코드는 false를, 그렇지 않으면 true를 반환해야합니다. 마우스와 터치가있는 장치의 경우 false를 반환해야합니다 (터치 만이 아님)

참고로, 터치 인터페이스는 키보드 전용 장치에도 적합 할 수 있으므로 감지하려는 마우스가 더 적습니다.

요구를보다 명확하게하기 위해 구현하려는 API는 다음과 같습니다.

// Level 1


// The current answers provide a way to do that.
hasTouch();

// Returns true if a mouse is expected.
// Note: as explained by the OP, this is not !hasTouch()
// I don't think we have this in the answers already, that why I offer a bounty
hasMouse();

// Level 2 (I don't think it's possible, but maybe I'm wrong, so why not asking)

// callback is called when the result of "hasTouch()" changes.
listenHasTouchChanges(callback);

// callback is called when the result of "hasMouse()" changes.
listenHasMouseChanges(callback);


하나의 앱을 데스크톱과 모바일 / 터치 모두에 적용 할 수 있지만 각각 다른 동작을 원한다면 디자인을 다시 생각해야한다고 생각합니다. "javascript detect mouse"에 대한 Google의 빠른 검색은 quirksmode.org에서 마우스의 다양한 상태 (클릭, 위치, 등)이지만 ZERO는 마우스가 실제로 존재하는지 여부를 나타냅니다.
davethegr8

24
어쩌면 구글이 여기에서 요청한 것을 도와주지 않았기 때문일 수 있습니다.
nraynaud

2
jquery에서 문서 mouseenter를 사용해 보셨습니까? $ (document) .mouseenter (function (e) {alert ( "mouse");});
Parag Gajjar

4
몇 분 안에 약 12 ​​개의 유망한 길을 고려하여 각각을 거부 한 후,이 질문은 저를 상당히 화려하게 만들어줍니다.
Jordan Gray

답변:


65

가장 큰 문제는 다음과 같은 다른 종류의 장치 / 사용 사례가 있다는 것입니다.

  1. 마우스 및 키보드 (데스크톱)
  2. 터치 만 (전화 / 태블릿)
  3. 마우스, 키보드 및 터치 (터치 랩톱)
  4. 터치 및 키보드 (태블릿의 블루투스 키보드)
  5. 마우스 만 (사용 불가능한 사용자 / 브라우징 환경 설정)
  6. 키보드 만 (사용 불가능한 사용자 / 브라우징 환경 설정)
  7. 터치 및 마우스 (예 : Galaxy Note 2 펜의 호버 이벤트)

더 나쁜 것은,이 클래스 중 일부에서 다른 클래스로 전환 할 수 있거나 (마우스에 연결하고 키보드에 연결) 사용자가 화면에 닿아 화면을 터치 할 때까지 일반 랩톱에있는 것처럼 보일 수 있습니다.

브라우저에 이벤트 생성자가 존재하는 것이 앞으로 나아갈 수있는 좋은 방법이 아니라고 가정합니다 (일관되지 않음). 또한 매우 구체적인 이벤트를 추적하거나 위의 몇 가지 클래스 만 배제하지 않는 한 이벤트 자체를 사용하는 것이 완벽한 증거는 아닙니다.

예를 들어, 사용자가 실제 마우스 이동 (터치 이벤트에서 잘못된 마우스 이동이 아님)을 발견 한 경우 http://www.html5rocks.com/en/mobile/touchandmouse/를 참조하십시오 . )을 .

그리고 뭐?

호버 스타일을 사용 하시겠습니까? 버튼을 더 추가 하시겠습니까?

어느 쪽이든 이벤트가 발생할 때까지 기다려야하므로 유리 컵 시간이 늘어나고 있습니다.

그러나 고귀한 사용자가 마우스를 뽑고 풀 터치하고 싶을 때 어떤 일이 벌어 지나요? 지금 밀려 난 인터페이스를 만질 때까지 기다렸다가 지금 붐비는 UI를 찾기 위해 노력한 후 바로 변경 하시겠습니까?

글 머리 기호 형식으로 https://github.com/Modernizr/Modernizr/issues/869#issuecomment-15264101 에서 stucox를 인용 하십시오.

  • 마우스의 존재를 감지하고 싶다
  • 아마도 이벤트가 시작되기 전에는 감지 할 수 없습니다
  • 따라서 우리가 감지하는 것은이 세션에서 마우스가 사용 된 경우입니다. 즉, 페이지로드에서 즉시 발생하지는 않습니다.
  • 또한 마우스가 없다는 것을 감지하지 못할 수도 있습니다. 사실까지는 정의되지 않을 것입니다.
  • 그리고 아마도 세션 중 마우스 연결이 끊어 졌는지 감지 할 수 없습니다. 사용자가 마우스를 포기하는 것과 구분할 수 없을 것입니다

따로 : 브라우저는 사용자가 마우스를 연결하거나 키보드에 연결할 때 알고 있지만 JavaScript에 노출하지 않습니다 .. dang!

이것은 다음으로 이어질 것입니다 :

특정 사용자의 현재 기능을 추적하는 것은 복잡하고 신뢰할 수 없으며 모호한 장점이 있습니다.

그러나 점진적 향상이라는 아이디어는 여기서도 잘 적용됩니다. 사용자의 상황에 관계없이 원활하게 작동하는 경험을 구축하십시오. 그런 다음 브라우저 기능 / 미디어 쿼리를 기반으로 가정하여 가정 된 상황에서 상대적으로 기능을 추가합니다. 마우스의 존재는 여러 장치의 서로 다른 사용자가 웹 사이트를 경험하는 다양한 방법 중 하나 일뿐입니다. 커널에 장점이있는 무언가를 만들고 사람들이 버튼을 클릭하는 방식에 대해 너무 걱정하지 마십시오.


3
좋은 대답입니다. 바라건대, 사용자는 항상 화면을 가지고 있습니다! 사용자의 현재 상호 작용 모드에 맞는 인터페이스를 구축하는 것이 합리적이라고 생각합니다. 터치 랩톱에서는 :hover사용자가 마우스에서 터치로 전환 할 때 앱 (예 : 요소 및 이와 유사한 것) 을 조정하는 것이 좋습니다 . 사용자가 현재 정확히 같은 시간에 마우스 + 터치를 사용하고있는 것 같지 않습니다 (동일한 컴퓨터에 2 개의 마우스를 연결 한 것과 같습니다)
Sebastien Lorber

@SebastienLorber-당신에게 그것을 나누는 것을 싫어하지만 사용자 항상 화면을 가질 필요 는 없습니다 . ( 스크린 리더가 사용자 컴퓨터에서 실행 중인지 감지하기 위해 자바 스크립트를 사용할 수 있습니까? )
ashleedawg

57

문서에서 mousemove 이벤트를 수신하는 것은 어떻습니까. 그런 다음 해당 이벤트가 들릴 때까지 장치가 터치 또는 키보드 전용이라고 가정합니다.

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

(여기서 listenunlisten대리자 addEventListener또는 attachEvent적절한.)

바라건대 이것은 시각적으로 너무 많은 영향을 미치지 않을 것입니다. 모드에 따라 대규모 재 레이아웃이 필요하다면 짜증날 것입니다 ...


2
좋은 생각이지만 안타깝게도 응용 프로그램의 UI가 마우스를 사용할 수 있는지 여부에 따라 응용 프로그램의 UI가 사용되지 않으면 응답 지연으로 인해 사용할 수 없게됩니다. 이는 응용 프로그램이 손상된 경우 특히 그렇습니다. 마우스가 iframe 자체 위로 이동합니다.
Jon Gjengset

7
응용 프로그램이 시작 화면과 "계속"버튼으로 시작하는 경우 작동 할 수 있습니다. 마우스가 첫 번째 마우스 다운 이벤트 전에 움직이면 마우스가있는 것입니다. 버튼이 마우스 바로 아래에로드되어 있고 사용자에게 매우 안정적인 손이있는 경우에만 실패합니다 (이동하는 1 픽셀도 선택해야 함).
SpliFF

49
좋은 생각이지만 테스트에서 작동하지 않는 것 같습니다 . iPad가이 이벤트를 트리거합니다.
Jeff Atwood

3
@JeffAtwood 당신의 사건에서 무엇을 했습니까?
Michael Haren 2019

2
iPad는 mousedown 이벤트 직전에 mousemove 이벤트를 트리거합니다. mousedown count> 0 및 mousedown count == mousemove count가 마우스를 감지하지 않는 좋은 방법이라는 것을 알았습니다. 실제 마우스로는 이것을 복제 할 수 없습니다.
피터 우스터

36

2018 년 현재 브라우저에 마우스 (또는 유사한 입력 장치)가 있는지 감지하는 좋고 신뢰할 수있는 방법이 있습니다 : CSS4 미디어 상호 작용 기능 은 현재 거의 모든 최신 브라우저 (IE 11 및 특수 모바일 브라우저 제외)에서 지원됩니다.

W3C :

포인터 미디어 기능은 마우스와 같은 포인팅 장치의 존재 및 정확성을 쿼리하는 데 사용됩니다.

다음 옵션을 참조하십시오.

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

미디어 쿼리는 JS에서도 사용할 수 있습니다.

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

관련 :

W3 설명서 : https://www.w3.org/TR/mediaqueries-4/#mf-interaction

브라우저 지원 : https://caniuse.com/#search=media%20features

비슷한 문제 : 클라이언트 장치가 : hover 및 : focus 상태를 지원하는지 감지


나는 개인적 으로이 답변을 좋아하지만 현재 (10/19) 현재 @media hover 및 pointer CSS 쿼리는 caniuse.com에 따르면 전 세계 장치의 ~ 85 %에서만 사용할 수 있습니다. 확실히 나쁘지 않은데, 95 % 이상이 바람직하다. 바라건대 이것은 곧 장치에서 표준이 될 것입니다.
MQuiggGeorgia

1
@MQuiggGeorgia 기본적으로 나는 당신의 비판에 기본적으로 동의합니다, 그것은 아직 모든 곳에서 지원되지는 않습니다. 여전히 나를 위해 caniuse.com은 91.2 % ( caniuse.com/#feat=css-media-interaction )를 지원한다고 말합니다 . 자세히 살펴보면 IE 11 및 모바일의 특수 평면 브라우저를 제외한 모든 곳에서 지원됩니다. 공평하게 말하면 Microsoft가 오래 전에 IE 기능 구현을 중단했기 때문에 모든 최신 기능에 해당됩니다. IE 11의 경우 다른 답변에서 폴백을 사용할 수 있습니다.
Blackbam

23

@Wyatt의 대답은 훌륭하고 우리가 생각할 많은 것을 제공합니다.

제 경우에는 첫 번째 상호 작용을 듣고 행동을 설정하기로 결정했습니다. 따라서 사용자에게 마우스가 있어도 첫 번째 상호 작용이 터치 인 경우 터치 장치로 취급합니다.

이벤트가 처리되는 주어진 순서를 고려하십시오 .

  1. 터치 스타트
  2. 터치
  3. 터치
  4. 마우스 오버
  5. mousemove
  6. 마우스 다운
  7. 마우스
  8. 딸깍 하는 소리

마우스 이벤트가 터치 전에 트리거되면 에뮬레이트 된 이벤트가 아니라 실제 마우스 이벤트라고 가정 할 수 있습니다. 예 (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);
});

그것은 나를 위해 일했다


나를 위해 작동하지 않습니다, Ipad Safari (IOS8.3)는 또한이 발췌 문장으로 마우스를 감지합니다
netzaffin

3
@netzaffin. 의견을 보내 주셔서 감사합니다. 마우스 오버 대신 mousedown을 사용하면 더욱 일관된 것으로 나타났습니다. IOS에서이 바이올린을보고 결과를 알려주시겠습니까? 건배 jsfiddle.net/bkwb0qen/15/embedded/result
Hugo Silva

1
마우스로 터치 스크린을 사용하는 경우 먼저 사용 된 입력 방법 만 감지됩니다.
0xcaff

11

브라우저가 터치 가능한지 여부 만 감지 할 수 있습니다. 실제로 터치 스크린이나 마우스가 연결되어 있는지 알 수있는 방법이 없습니다.

터치 기능이 감지되면 마우스 이벤트 대신 터치 이벤트를 수신하여 사용의 우선 순위를 지정할 수 있습니다.

터치 기능 크로스 브라우저를 감지하려면

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

그런 다음 이것을 사용하여 확인할 수 있습니다.

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

또는들을 이벤트를 선택하십시오.

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

또는 터치 대 비 터치에 대해 별도의 접근 방식을 사용하십시오.

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
}

마우스의 경우 마우스 사용 여부를 감지 할 수 있습니다. 마우스가 사용법에 의해 감지되었음을 나타내는 전역 플래그를 설정할 수 있습니다 (기존 답변과 유사하지만 약간 단순화 됨).

var hasMouse = false;

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

(하나는 터치로 트리거 할 수 mouseup있거나 포함 할 수 없으므로 mousedown)

브라우저는 사용중인 시스템의 하드웨어 기능과 같은 기능을 감지하는 데 필요한 저수준 시스템 API에 대한 액세스를 제한합니다.

플러그인 / 확장 프로그램을 작성하여 액세스 할 수는 있지만 JavaScript 및 DOM을 통해 이러한 감지는이 목적으로 제한되며 다양한 OS 플랫폼에 맞는 플러그인을 작성해야합니다.

결론적으로, 이러한 탐지는 "좋은 추측"에 의해서만 추정 될 수 있습니다.


8

미디어 쿼리 레벨 4가 브라우저에서 사용할 수 있습니다, 우리는 마우스 장치를 탐지하기 위해 "포인터"와 "가져가"쿼리를 사용할 수 있습니다.

해당 정보를 Javascript와 실제로 통신하려면 CSS 쿼리를 사용하여 장치 유형에 따라 특정 스타일을 설정 한 다음 getComputedStyle Javascript를 하여 해당 스타일을 읽고 원래 장치 유형을 파생시킬 수 있습니다.

그러나 언제든지 마우스를 연결 하거나 분리 할 수 있으며 사용자는 터치와 마우스를 전환하려고 할 수 있습니다. 따라서이 변경 을 감지 하고 인터페이스 변경 또는 자동 변경을 제안 해야 할 수도 있습니다 .


1
특히, any-pointerany-hover 모든 적용 가능한 장치 기능을 조사하게됩니다. 앞으로이 문제를 어떻게 해결할 수 있는지 엿볼 수 있습니다. :)
Jordan Gray

2
window.matchMedia ( "(any-pointer : coarse)"). matches === true?
4esn0k

7

어쨌든 인터페이스 간을 전환 할 수있는 방법을 제공 할 계획이므로 사용자에게 링크 나 버튼을 클릭하여 올바른 버전의 응용 프로그램을 "입력"하도록 요청하는 것이 가능합니까? 그러면 향후 방문에 대한 선호도를 기억할 수 있습니다. 첨단 기술은 아니지만 100 % 신뢰할 수 있습니다 :-)


2
실제로 꽤 좋은 제안이지만 사용자가 실제 인터페이스에 도달하기까지 시간이 지연됩니다. 또한 초기 선택 후 전환 방법을 제공해야합니다. 단순히 감지 할 수있는 것보다 더 많은 작업을하게됩니다 ..
Jon Gjengset

1
항상 바보는 아니지만 사용자에게 묻는 것이 가장 좋은 방법이며 업그레이드 알림을받을 수있는 편리한 장소를 제공합니다. 당신이 "문제"를 생각하고 있다고 생각합니다 ..
T4NK3R

4

@SamuelRossille 유감스럽게도 마우스의 존재 (또는 부족)를 노출시키는 브라우저는 없습니다.

따라서, 우리는 기존 옵션 인 이벤트로 최선을 다해야합니다. 나는 그것이 당신이 찾고있는 것이 아니라는 것을 알고 있습니다 ... 현재는 이상적이지 않다는 데 동의했습니다.

주어진 순간에 사용자가 마우스를 사용하는지 아니면 터치를 사용하는지 파악하기 위해 최선을 다할 수 있습니다. 다음은 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');

이제 usingMouse ()usingTouch () 를 바인딩 / 구독 하거나 body.mouse 클래스로 인터페이스 스타일을 지정할 수 있습니다. 마우스 커서가 감지되고 터치 스타트되면 인터페이스가 앞뒤로 전환됩니다.

바라건대 우리는 곧 브라우저 공급 업체의 더 나은 옵션을 갖게 될 것입니다.


2

Tera-WURFL브라우저 서명 을 데이터베이스와 비교 하여 사이트 방문하는 장치의 기능을 알려줍니다 . 그것에게 무료로보세요!


1
터치 스크린과 마우스가 있거나없는 장치에서는 작동하지 않습니다. 예를 들어, 데스크탑 Windows 컴퓨터는 터치 스크린에 연결될 수 있지만 일반적으로 마우스도 있지만 태블릿은 Windows를 실행하지만 마우스는 연결되어 있지 않을 수 있습니다.
Jon Gjengset

@Jonhoo 데스크톱 운영 체제에 마우스가 연결되어 있다고 가정하십시오. 결국 터치 스크린을 염두에두고 개발되지 않은 광범위한 소프트웨어를 지원해야합니다.
Gigi

1
일반 Windows 8을 실행하는 태블릿은 어떻습니까? 아니면 리눅스? 아니면 안드로이드를 실행하는 노트북?
Jon Gjengset 2012

2
@Jonhoo 분명히이 방법은 최적의 방법은 아니지만 그 방법을 알 수있는 이식 가능한 방법은 없습니다 (아직). Android를 사용하는 랩톱을 실행하는 경우 터치 가능하다고 가정하십시오. Windows8 태블릿을 실행하는 경우 마우스를 사용할 수 있다고 가정합니다 (OS는 비 터치 프로그램의 경우 마우스를 에뮬레이션해야 함).
Gigi

이제는 너무 오래되어 더 이상 관련이 없습니다.
엔지니어

2

터치 감지 및 / 또는 마우스 움직임에 반응 할 수있는 기능을 감지하는 것이 어떻습니까?

// 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
일부 브라우저 (예 : IE9)는 함수가 트리거되지 않더라도 함수가 존재한다고보고하기 때문입니다. 나는 이것이 또한 "올바른"행동이라고 믿는다.
Jon Gjengset 2012

왜 함수를 사용하겠습니까? 단지 has_touch = 'ontouchstart' in window등등 충분하고 있습니다.
vsync 2018

글쎄, 적어도 OS X 용 Chrome 47에서 작동합니다. ontouchstart를보고하지 않습니다.
phreakhead

2

이것은 비슷한 상황에서 저에게 효과적이었습니다. 기본적으로 마우스 다운이나 마우스 업을 거치지 않고 일련의 짧은 마우스 동작이 연속적으로 표시 될 때까지 사용자에게 마우스가 없다고 가정합니다. 매우 우아하지는 않지만 작동합니다.

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

다른 사람들이 지적했듯이, 마우스가 있는지 여부를 확실하게 감지하는 것은 신뢰할 수 없습니다. 장치에 따라 쉽게 변경할 수 있습니다. 적어도 문서 규모에서 부울 true 또는 false로 안정적으로 수행 할 수없는 것입니다.

터치 이벤트 및 마우스 이벤트는 독점적입니다. 따라서 이것은 다른 행동을 취하는 데 다소 도움이 될 수 있습니다. 문제는 터치 이벤트가 마우스 업 / 다운 / 이동 이벤트에 더 가깝고 클릭 이벤트를 트리거한다는 것입니다.

당신의 질문에서 당신은 당신이 미리보기를 가리켜보고 싶다고 말합니다. 그 외에도 나는 당신의 인터페이스에 대한 다른 구체적인 사항을 모른다. 나는 가정하고있다 클릭이 때문에 호버 미리보기의 다른 작업을 수행하는 동안, 당신은 미리보기에 탭을 원하는 마우스의 부족으로 그.

이 경우 감지에 다소 게으른 접근 방식을 취할 수 있습니다.

onclick 이벤트는 항상 마우스가있는 onmouseover 이벤트보다 우선합니다. 마우스는 클릭 한 요소 위에 있습니다.

문서 전체의 onmousemove 이벤트로이를 수행 할 수 있습니다. event.target마우스가 상주하는 요소를 기록하는 데 사용할 수 있습니다 . 그런 다음 onclick 이벤트 내에서 마우스가 실제로 클릭되는 요소 (또는 요소의 자식) 위에 있는지 여부를 확인할 수 있습니다.

여기에서 클릭 이벤트에 의존하고 결과에 따라 A 또는 B 조치를 수행하도록 선택할 수 있습니다. 일부 터치 장치에서 클릭 이벤트가 발생하지 않으면 B 동작은 아무 것도 될 수 없습니다 (대신 ontouch * 이벤트에 의존해야 함).


0

(물론 내 지식으로는) 터치 전용 장치를 식별하는 것이 가능하지 않다고 생각합니다. 주요 문제는 모든 마우스 및 키보드 이벤트가 터치 장치에서도 발생한다는 것입니다. 다음 예를 참조하면 터치 장치에 대해 두 경고가 모두 true를 반환합니다.

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가 다음 true을 반환 합니다'onmousedown' in window
vsync

0

내 생각에 가장 좋은 아이디어는 mousemove듣는 사람 (현재 가장 좋은 대답)입니다. 나는이 방법을 약간 조정해야한다고 생각합니다. 이 iOS 토론 에서 볼 수 있듯이 터치 기반 브라우저는 mousemove 이벤트를 에뮬레이트하는 것이 사실입니다. 이므로 조금 조심해야합니다.

터치 기반 브라우저는 사용자가 화면을 누를 때 (사용자의 손가락이 눌린 경우)에만이 이벤트를 에뮬레이트합니다. 이것은 우리가 mousemove 처리기 동안 테스트를 추가하여 이벤트 중에 어떤 마우스 버튼이 눌 렸는지 (있는 경우) 확인해야한다는 것을 의미합니다. 마우스 버튼을 누르지 않으면 실제 마우스가 있다고 가정 할 수 있습니다. 마우스 버튼이 눌려 있으면 테스트는 확정되지 않습니다.

그렇다면 어떻게 구현할까요? 이 질문 은 mousemove 중 어떤 마우스 버튼이 눌 렸는지 검사하는 가장 안정적인 방법은 실제로 문서 레벨에서 mousemove, mousedown 및 mouseup의 3 가지 이벤트를 수신하는 것임을 보여줍니다. 위와 아래는 전역 부울 플래그 만 설정합니다. 이동이 테스트를 수행합니다. 움직임이 있고 부울이 거짓이면 마우스가 있다고 가정 할 수 있습니다. 정확한 코드 예제는 질문을 참조하십시오.

마지막 설명입니다.이 테스트는로드 시간에 수행 할 수 없기 때문에 이상적이지 않습니다. 따라서 이전에 제안한대로 점진적 향상 방법을 사용합니다. 기본적으로 마우스 특정 호버 인터페이스를 지원하지 않는 버전이 표시됩니다. 마우스가 발견되면 런타임시 JS를 사용하여이 모드를 사용하십시오. 사용자에게 가능한 한 매끄럽게 표시되어야합니다.

사용자 구성의 변경을 지원하기 위해 (예 : 마우스 연결이 끊어짐) 주기적으로 다시 테스트 할 수 있습니다. 이 경우 단순히 사용자에게 2 가지 모드에 대해 알리고 사용자가 수동으로 전환 할 수 있도록하는 것이 더 낫다고 생각하지만 (항상 되돌릴 수있는 모바일 / 데스크탑 선택과 유사).


좋은 해결 방법을 제안 해 주셔서 감사합니다. 주요 문제가 해결되지 않는 것 같습니다. 다음 중 하나에 의존해야합니다
Samuel Rossille

불행히도 ipad를 클릭하면 mousemove가 트리거됩니다. 시뮬레이터로만 테스트되었습니다. hasMouse ()의 경우 if (! ( 'ontouchstart'in window))를 사용하여 true를 반환했습니다. 터치 지원 랩톱에서는 작동하지 않습니다.
Chris Gunawardena

@Chris G-iPad 지옥 ... (벽에 머리를 대고)
vsync

0

다양한 PC, Linux, iPhone, Android 전화 및 탭에서 일부 테스트를 실행했습니다. 쉬운 방탄 솔루션이 없다는 것이 이상합니다. Touch가 있고 마우스가없는 일부 응용 프로그램에 여전히 Touch 및 Mouse 이벤트가있는 경우 문제가 발생합니다. 마우스 전용 및 터치 전용 인스턴스를 지원하고자하므로 둘 다 처리하려고하지만 두 번의 사용자 상호 작용이 발생합니다. 장치에 마우스가없는 것을 알 수 있으면 가짜 / 삽입 된 마우스 이벤트를 무시하는 것을 알 수 있습니다. MouseMove가 발생하면 설정 플래그를 시도했지만 일부 브라우저는 MouseUp 및 MouseDown뿐만 아니라 가짜 MouseMove를 발생시킵니다. 타임 스탬프 검사를 시도했지만 이것이 너무 위험하다고 생각했습니다. 결론 : 가짜 마우스 이벤트를 만든 브라우저는 항상 MouseDown을 삽입하기 직전에 단일 MouseMove를 삽입했습니다. 제 경우의 99.99 %에서 실제 마우스가있는 시스템에서 실행할 때는 여러 개의 연속적인 MouseMove 이벤트가 있습니다 (최소 2 회). 따라서 시스템에서 두 개의 연속적인 MouseMove 이벤트가 발생하는지 추적하고이 조건이 충족되지 않으면 마우스가 존재하지 않는 것으로 선언하십시오. 이것은 아마도 너무 간단하지만 모든 테스트 설정에서 작동합니다. 더 나은 솔루션을 찾을 때까지 계속 사용하겠습니다. -짐 W


0

마우스 사용을 감지하는 jQuery의 간단한 솔루션으로 모바일 장치가 'mousemove'이벤트를 트리거하는 문제를 해결합니다. 터치 스타트 리스너를 추가하여 마우스 이동 리스너를 제거하면 터치시 트리거되지 않습니다.

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

물론 장치는 여전히 터치 앤 마우스 일 수 있지만 위의 방법으로 실제 마우스를 사용할 수 있습니다.


0

내가 아주 우아하다고 생각하는 해결책을 찾았습니다.

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

동일한 문제가 발생하여 단일 터치가 클릭으로 등록되었습니다. 내가 가장 많이 투표 한 답변에 대한 의견을 읽은 후 내 해결책을 찾았습니다.

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

내가 찾은 유일한 문제는 터치 이벤트를 올바르게 감지하기 위해 스크롤 할 수 있어야한다는 것입니다. 단일 탭 (터치)으로 인해 문제가 발생할 수 있습니다.


0

Phonegap 앱 에서이 문제를 알아내는 데 몇 시간을 보냈 으며이 해킹을 생각해 냈습니다. 트리거 된 이벤트가 "수동적"이벤트 인 경우 콘솔 경고를 생성합니다. 즉, 변경 사항이 발생하지 않지만 작동합니다! 개선이나 더 나은 방법에 대한 아이디어가 필요합니다. 그러나 이것은 효과적으로 $ .touch ()를 보편적으로 사용할 수있게합니다.

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

여기서 볼 수있는 주요 문제는 대부분의 터치 장치가 코어 터치 장치와 함께 마우스 이벤트를 발생시키는 것입니다 (touchstart-> mousedown, touchmove-> mousemove 등). 키보드의 경우에만 현대의 키보드에는 일반 브라우저가 있으므로 MouseEvent 클래스의 존재를 감지 할 수도 없습니다.

내 생각에 덜 고통스러운 해결책은 시작시 메뉴를 표시하고 (키보드 전용 사용자를위한 'alt'관리 기능을 사용하여) 로컬 저장 장치 / 쿠키 / 서버 측에 선택 항목을 저장하거나 다음 선택을 다음과 동일하게 유지하는 것입니다 방문자가 온 시간.


-4

이 방법을 사용하지 않는 것이 좋습니다. 터치 스크린, 데스크탑 크기의 장치를 고려하면 해결해야 할 다른 문제가 있습니다.

마우스없이 앱을 사용할 수있게하십시오 (예 : 마우스 오버 미리보기 없음).


1
그것이 바로 내가하려는 일입니다. 태블릿 (마우스 없음)과 마우스 모두에서 최상의 방법으로 작동하는 인터페이스를 만들려고하지만 인터페이스가 반드시 매우 다릅니다.
Jon Gjengset 2012

나는 광범위하게 동의합니다. DeviceAtlas와 같은 장치 감지를 사용하고로드시 제공된 인터페이스를 선택하는 것이 가장 좋습니다.
Teemu Ikonen

-4

나를 도와주는 스크립트를 추천하고 싶습니다 :

나는 충분한 결과없이 제안 된 모든 것을 읽고 시도했다.

그런 다음 좀 더 조사 하고이 코드를 발견했습니다 -device.js

나는 클라이언트의 웹 사이트에서 이것을 사용하여 마우스 존재를 감지합니다.
( 클래스 <html>가 있어야 함 desktop) 꽤 좋아 보입니다. touch지원 을 위해 정기적으로 확인 'ontouchend' in document하고 두 가지 감지 정보를 사용하여 필요한 특정 것을 가정합니다.


이는 이미이 주제에서 여러 번 제기 된 UA 스니핑과 동일합니다. Windows 8과 같이 마우스와 터치가있는 장치의 경우에는 문제가 해결되지 않으며 미래의 증거는 아닙니다.
휴고 실바

나는 당신이 클라이언트의 응용 프로그램에서 언급 한이 정확한 사례를 해결하기 위해 그것을 사용하며 잘 작동합니다. 그것은 개발자에 의해 유지되기 때문에 미래의 증거입니다.
vsync

2
내가 언급 한 경우 (터치 가능 랩톱)는 마우스를 사용할 수 없지만 스크립트에서 "데스크톱"으로 식별됩니다. "그것은 개발자에 의해 유지되기 때문에 미래의 증거입니다"-나는 당신이 여기서 "미래의 증거"의 요점을 완전히 놓쳤다 고 생각합니다. 그리고 당신이 말한대로 모든 것을 읽고 시도했다면 Gigi의 대답이 이미 UA 스니핑을 암시한다는 것을 알았을 것입니다.
휴고 실바

-7

OS / 브라우저 유형을 감지하는 대신 마우스 오버 기능이 지원되는지 감지하는 것이 일반적으로 더 좋습니다. 다음과 같이 간단하게 수행 할 수 있습니다.

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

다음 을 수행하지 않아야 합니다.

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

후자는 실제로 메소드의 존재를 확인하는 대신 메소드를 호출합니다.

자세한 내용은 여기를 참조하십시오 : http://www.quirksmode.org/js/support.html


2
나는 당신의 게시물에서 무엇을 얻을지 모르겠지만 if ( 'onmouseover'in $ ( 'body') [0]) alert ( 'onmouseover'); 너무 표시 아이폰에 메시지를
nraynaud

1
이것은 거의 모든 브라우저에서 마우스 오버 기능이 정의되어 있는지 확인합니다. 마우스가 실제로 있는지 감지하지 않습니다.
Jon Gjengset
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.