Wyłącz efekty najechania kursorem w przeglądarkach mobilnych


113

Piszę witrynę sieci Web, która ma być używana zarówno z komputerów stacjonarnych, jak i tabletów. Kiedy jest odwiedzany z pulpitu, chcę, aby klikalne obszary ekranu były podświetlane z :hoverefektami (inny kolor tła itp.). Na tablecie nie ma myszy, więc nie chcę żadnych efektów najechania kursorem.

Problem polega na tym, że kiedy dotykam czegoś na tablecie, przeglądarka ewidentnie ma jakiś „niewidoczny kursor myszy”, który przesuwa się do miejsca, w które stuknąłem, a następnie zostawia go tam - więc to, co właśnie stuknąłem, zapala się efekt najechania, dopóki nie stuknę czegoś innego.

Jak mogę uzyskać efekty najechania kursorem, gdy używam myszy, ale je wyłączyć, gdy używam ekranu dotykowego?

Na wypadek, gdyby ktoś myślał o zasugerowaniu tego, nie chcę korzystać z węszenia klienta użytkownika. To samo urządzenie może mieć zarówno ekran dotykowy, jak i mysz (może nie tak powszechne obecnie, ale znacznie bardziej w przyszłości). Nie interesuje mnie urządzenie, interesuje mnie jak jest aktualnie używane: mysz czy ekran dotykowy.

Próbowałem już podpinania się touchstart, touchmoveoraz touchendwydarzenia i powołanie preventDefault()na wszystkie z nich, które nie tłumią „niewidzialny kursor myszy” na jakiś czas; ale jeśli szybko stuknę tam iz powrotem między dwoma różnymi elementami, po kilku stuknięciach zacznie przesuwać „kursor myszy” i tak czy inaczej podświetla efekty najechania - to tak, jakby mój preventDefaultnie zawsze był honorowany. Nie będę Cię zanudzać szczegółami, chyba że będzie to konieczne - nie jestem nawet pewien, czy jest to właściwe podejście; jeśli ktoś ma prostsze rozwiązanie, mam wszystkie uszy.


Edycja: Można to odtworzyć za pomocą standardowego CSS bog :hover, ale oto krótka reprodukcja w celach informacyjnych.

<style>
  .box { border: 1px solid black; width: 150px; height: 150px; }
  .box:hover { background: blue; }
</style>
<div class="box"></div>
<div class="box"></div>

Jeśli najedziesz kursorem myszy na jedno z pól, pojawi się niebieskie tło, które chcę. Ale jeśli dotkniesz któregokolwiek z pól, również pojawi się niebieskie tło, czemu staram się zapobiec.

Opublikowałem tutaj również próbkę , która wykonuje powyższe, a także przechwytuje zdarzenia myszy jQuery. Możesz go użyć, aby zobaczyć, że zdarzenia dotknięcia również będą uruchamiane mouseenter, mousemovei mouseleave.


7
@Blender, czy przeczytałeś pytanie? Wyjaśniłem już, dlaczego węszenie klienta użytkownika to zły wybór.
Joe White

Hej Joe, czy znalazłeś na to jakieś rozwiązanie?
Ismatjon,

Szukałem tego rodzaju pytania, cieszę się, że je znalazłem!
agpt

Zobacz także to pytanie, które dotyczy wyłączania wskaźnika na dowolnym urządzeniu obsługującym dotyk, nie tylko mobilnym: stackoverflow.com/questions/23885255/ ...
blade

Odpowiedzi:


83

Z twojego pytania wynika, że ​​efekt najechania kursorem zmienia zawartość twojej strony. W takim przypadku radzę:

  • Dodaj efekty najechania na touchstarti mouseenter.
  • Usuń unosić skutki mouseleave, touchmovei click.

Alternatywnie możesz edytować swoją stronę, aby nie zmieniała treści.

tło

Aby zasymulować mysz, przeglądarki, takie jak Webkit mobile, uruchamiają następujące zdarzenia, jeśli użytkownik dotknie i puści palec na ekranie dotykowym (takim jak iPad) (źródło: Touch And Mouse na html5rocks.com):

  1. touchstart
  2. touchmove
  3. touchend
  4. 300 ms opóźnienia, gdy przeglądarka upewnia się, że jest to jedno dotknięcie, a nie podwójne dotknięcie
  5. mouseover
  6. mouseenter
    • Uwaga : W przypadku mouseover, mouseenterczy mousemovezdarzenie zmienia zawartość strony, następujące zdarzenia nie są wypalane.
  7. mousemove
  8. mousedown
  9. mouseup
  10. click

Wydaje się, że nie jest możliwe po prostu nakazanie przeglądarce pominięcia zdarzeń myszy.

Co gorsza, jeśli zdarzenie najechania kursorem myszy zmieni zawartość strony, zdarzenie kliknięcia nigdy nie zostanie uruchomione, jak wyjaśniono w Przewodniku po treściach internetowych Safari - Obsługa zdarzeń , w szczególności na rysunku 6.4 w Zdarzeniach jednym palcem . Czym dokładnie jest „zmiana treści”, zależy od przeglądarki i wersji. Odkryłem, że w iOS 7.0 zmiana koloru tła nie jest (lub już nie?) Zmianą treści.

Wyjaśnienie rozwiązania

Przypomnę:

  • Dodaj efekty najechania na touchstarti mouseenter.
  • Usuń unosić skutki mouseleave, touchmovei click.

Zauważ, że nie ma żadnej akcji touchend!

To oczywiście działa w przypadku zdarzeń myszy: mouseenteri mouseleave(nieco ulepszone wersje mouseoveri mouseout) są uruchamiane i dodają i usuwają dymek.

Jeśli użytkownik faktycznie jest clicklinkiem, efekt najechania kursorem jest również usuwany. Zapewnia to, że zostanie usunięty, jeśli użytkownik naciśnie przycisk Wstecz w przeglądarce internetowej.

Działa to również w przypadku zdarzeń dotykowych: przy Touchstart dodawany jest efekt najechania. To jest '' 'nie' '' usunięte po dotknięciu. Jest on ponownie dodawany mouseenter, a ponieważ nie powoduje to żadnych zmian treści (zostało już dodane), clickzdarzenie jest również uruchamiane, a łącze jest śledzone bez konieczności ponownego klikania przez użytkownika!

300 ms opóźnienia, które przeglądarka ma między touchstartzdarzeniem i clickjest faktycznie dobrze wykorzystywane, ponieważ efekt najechania kursorem będzie wyświetlany w tym krótkim czasie.

Jeśli użytkownik zdecyduje się anulować kliknięcie, ruch palcem zrobi to normalnie. Zwykle jest to problem, ponieważ żadne mouseleavezdarzenie nie jest uruchamiane, a efekt zawisu pozostaje na miejscu. Na szczęście można to łatwo naprawić, usuwając efekt najechania na touchmove.

Otóż ​​to!

Zwróć uwagę, że możliwe jest usunięcie opóźnienia 300 ms, na przykład przy użyciu biblioteki FastClick , ale jest to poza zakresem tego pytania.

Alternatywne rozwiązania

Znalazłem następujące problemy z następującymi alternatywami:

  • wykrywanie przeglądarki: wyjątkowo podatne na błędy. Zakłada się, że urządzenie ma mysz lub dotyk, podczas gdy kombinacja obu będzie coraz bardziej powszechna, gdy wyświetlacze dotykowe będą się rozprzestrzeniać.
  • Wykrywanie mediów CSS: jedyne znane mi tylko rozwiązanie CSS. Wciąż podatny na błędy i nadal zakłada, że ​​urządzenie ma mysz lub dotyk, podczas gdy oba są możliwe.
  • Emuluj zdarzenie kliknięcia w touchend: Spowoduje to niepoprawne podążanie za linkiem, nawet jeśli użytkownik chciał tylko przewijać lub powiększać, bez zamiaru klikania łącza.
  • Użyj zmiennej, aby powstrzymać zdarzenia myszy: Ustawia zmienną w, touchendktóra jest używana jako warunek jeśli w kolejnych zdarzeniach myszy, aby zapobiec zmianom stanu w tym momencie. Zmienna jest resetowana w przypadku kliknięcia. Zobacz odpowiedź Waltera Romana na tej stronie. To przyzwoite rozwiązanie, jeśli naprawdę nie chcesz efektu najechania na interfejsy dotykowe. Niestety, to nie działa, jeśli a touchendjest uruchamiane z innego powodu i nie jest uruchamiane żadne zdarzenie kliknięcia (np. Użytkownik przewinął lub powiększył), a następnie próbuje podążać za linkiem za pomocą myszy (tj. Na urządzeniu z myszą i interfejsem dotykowym ).

Dalsze czytanie


1
Niezła odpowiedź. Użyłem twoich skrzypiec, aby zacząć tworzyć własne rozwiązanie. Czasami jednak potrzebny jest dotyk. (gdy ruch dotykowy nie działa - tj. gdy użytkownik sam
wyjdzie

Świetna odpowiedź, ale w większości przypadków Sugeruję stosując touchend zamiast stanowi touchstartw większości przypadków uniknąć natychmiastowego działania wyzwalające, gdy użytkownik próbuje trzepnąć-przewijanie w górę lub w dół strony. Nadal będzie się zdarzać, ale jest mniej prawdopodobne, że rozproszy lub zmyli (zakładając, że jest to coś nieszkodliwego, jak wyświetlenie etykiety, a nie coś, o czym użytkownik musi wiedzieć)
user56reinstatemonica8

19

Jak mogę uzyskać efekty najechania kursorem, gdy używam myszy, ale je wyłączyć, gdy używam ekranu dotykowego?

Może nie myśl o tym tak bardzo, jak o wyłączaniu efektów najechania na ekrany dotykowe, ale jako o dodaniu efektów najechania na zdarzenia myszy?

Jeśli chcesz zachować :hoverefekty w swoim CSS, możesz określić różne style dla różnych mediów:

@media screen { /* hover styles here */ } 

@media handheld { /* non-hover styles here */ }

Tyle że niestety istnieje wiele urządzeń mobilnych, które to ignorują i po prostu korzystają z reguł ekranu. Na szczęście wiele nowszych przeglądarek na telefony komórkowe / tablety obsługuje bardziej wyszukane zapytania o media:

@media screen and (max-width:800px) { /* non-hover styles here */ }

Więc nawet jeśli część „ekranowa” lub „podręczna” zostanie zignorowana, „maksymalna szerokość” załatwi sprawę za Ciebie. Możesz po prostu założyć, że wszystko, co ma ekran mniejszy niż 800 pikseli, musi być tabletem lub telefonem i nie może używać efektów najechania kursorem. Dla rzadkich użytkowników, którzy używają myszy na urządzeniu o niskiej rozdzielczości, nie zobaczyliby efektów najechania kursorem, ale w przeciwnym razie Twoja witryna byłaby w porządku.

Chcesz dowiedzieć się więcej na temat zapytań medialnych? W Internecie jest mnóstwo artykułów na ten temat - oto jeden: http://www.alistapart.com/articles/return-of-the-mobile-stylesheet

Jeśli przesuniesz efekty najechania poza CSS i zastosujesz je w JavaScript, możesz powiązać się specjalnie ze zdarzeniami myszy i / lub znowu możesz po prostu przyjąć pewne założenia na podstawie rozmiaru ekranu, z najgorszym "problemem" użytkownik korzystający z myszy traci efekty najechania kursorem.


Chciałbym dodać efekty najechania tylko na zdarzenia myszy. Ale zdarzenia dotykowe naśladują zdarzenia myszy. Jeśli przechwycę zdarzenia dotyku i wywołam preventDefault(), czasami tłumi to zdarzenia myszy, ale jak powiedziałem w moim pytaniu, nie jest to wiarygodne.
Joe White

6
Jeśli chodzi o zapytania o media, co się dzieje, gdy pojawia się system Windows 8, a komputery mają zarówno ekrany dotykowe, jak i myszy? Jeśli użytkownik najedzie myszką, zobaczy kursor myszy i chcę uzyskać efekty najechania; jeśli dotykają ekranu dotykowego, nie chcę efektów najechania. Ale nie znalazłem niezawodnego sposobu na wykrycie różnicy między dotykiem a myszą.
Joe White

Cóż, być może programiści przeglądarek będą bardziej zmotywowani do bardziej spójnego wykrywania, gdy będą mieli więcej użytkowników na urządzeniach z dotykiem i myszą. Ale teraz? Robiłbym domysły na podstawie rozmiaru ekranu, ale w innych odpowiedziach jest inna rada. Przepraszam, nie mogę dalej pomóc.
nnnnnn

9

Napisałem następujący JS dla niedawnego projektu, który był stroną na komputery / urządzenia mobilne / tablety, które mają efekty najechania kursorem, które nie powinny pojawiać się po dotknięciu.

Poniższy mobileNoHoverStatemoduł ma zmienną preventMouseover(początkowo zadeklarowaną jako false), która jest ustawiana, truegdy użytkownik uruchomi touchstartzdarzenie na elemencie,$target .

preventMouseoverjest następnie ustawiany z powrotem na falsemoment uruchomienia mouseoverzdarzenia, co pozwala witrynie działać zgodnie z przeznaczeniem, jeśli użytkownik używa zarówno ekranu dotykowego, jak i myszy.

Wiemy, że mouseoverjest uruchamiany później z touchstartpowodu kolejności, w której są deklarowane init.

var mobileNoHoverState = function() {

    var hoverClass = 'hover',
        $target = $(".foo"), 
        preventMouseover = false;

    function forTouchstart() {
        preventMouseover = true;
    }

    function forMouseover() {
        if (preventMouseover === false) {
            $(this).addClass(hoverClass);
        } else {
            preventMouseover = false;
        }
    }

    function forMouseout() {
        $(this).removeClass(hoverClass);
    }

    function init() {
        $target.on({
            touchstart  : forTouchstart,
            mouseover   : forMouseover,
            mouseout    : forMouseout
        });                
    }

    return {
        init: init
    };
}();

Moduł jest następnie tworzony w dalszej części linii:

mobileNoHoverState.init();

„PreventMouseover jest następnie ustawiany z powrotem na true za każdym razem, gdy uruchamiane jest zdarzenie mouseover, co pozwala witrynie działać zgodnie z przeznaczeniem, jeśli użytkownik używa zarówno ekranu dotykowego, jak i myszy”. - Twój kod tego nie robi. Czy coś mi brakuje?
Redtopia

@Redtopia Dzięki za ostrzeżenie! Zaktualizowałem odpowiedź fragmentem kodu, który został pominięty.
Walter Roman

Nie potrzebujesz średników po deklaracji funkcji
nacholibre

@nacholibre Wprowadzono prawidłowe użycie średnika
Walter Roman

6

Naprawdę chciałem mieć czyste cssrozwiązanie tego problemu, ponieważ rozsypanie ciężkiego rozwiązania javascript wokół wszystkich moich poglądów wydawało się nieprzyjemną opcją. Wreszcie znalazłem zapytanie @ media.hover , które może wykryć „czy podstawowy mechanizm wprowadzania danych pozwala użytkownikowi na najechanie kursorem na elementy”. Pozwala to uniknąć urządzeń dotykowych, w przypadku których „zawisanie” jest bardziej emulowaną czynnością niż bezpośrednią funkcją urządzenia wejściowego.

Czyli na przykład, jeśli mam link:

<a href="/" class="link">Home</a>

Wtedy mogę bezpiecznie stylizować go tylko :hoverwtedy, gdy urządzenie z łatwością go obsługuje w ten sposób css:

@media (hover: hover) {
  .link:hover { /* hover styles */ }
}

Podczas gdy większość nowoczesnych przeglądarek obsługuje zapytania o funkcje multimediów, niektóre popularne przeglądarki, takie jak IE i Firefox , nie obsługują . W moim przypadku działa to dobrze, ponieważ zamierzałem obsługiwać tylko Chrome na komputerze stacjonarnym oraz Chrome i Safari na urządzeniach mobilnych.


Niezłe rozwiązanie, które wydaje się działać, gdy emulujesz urządzenia w Chrome Devtools. Ale nadal nie działa na Chrome na Androida :-(
Sjeiti

Myślę, że to najwygodniejsze i najbardziej poprawne rozwiązanie. Mam nadzieję, że wkrótce zostanie dodany do standardów W3C.
GProst

5

Moim rozwiązaniem jest dodanie klasy css hover-active do tagu HTML i użycie jej na początku wszystkich selektorów CSS za pomocą: hover i usuń tę klasę przy pierwszym zdarzeniu touchstart.

http://codepen.io/Bnaya/pen/EoJlb

JS:

(function () {
    'use strict';

    if (!('addEventListener' in window)) {
        return;
    }

    var htmlElement = document.querySelector('html');

    function touchStart () {
        document.querySelector('html').classList.remove('hover-active');

        htmlElement.removeEventListener('touchstart', touchStart);
    }

    htmlElement.addEventListener('touchstart', touchStart);
}());

HTML:

<html class="hover-active">

CSS:

.hover-active .mybutton:hover {
    box-shadow: 1px 1px 1px #000;
}

Zamiast słuchać zdarzenia dotykowego, możesz przeprowadzić test 'ontouchstart' in window. np.if ('ontouchstart' in window) document.querySelector('html').classList.remove('hover-active');
Yuval A.

@YuvalA. Powodem, dla którego czekam na zdarzenie dotykowe, jest to, że istnieją urządzenia ze wskaźnikiem i obsługą dotyku, a użytkownik używa wskaźnika, którego nie chcę usuwać dymka. Możliwe, że użytkownik użyje dotyku, a następnie wskaźnika, ale nie mam zbyt wiele do zrobienia
Bnaya

2

To, co zrobiłem, aby rozwiązać ten sam problem, to wykrywanie funkcji (używam czegoś w rodzaju ten kod ), sprawdzanie, czy zdefiniowano onTouchMove, a jeśli tak, dodaję do treści klasę css "touchMode", w przeciwnym razie dodaję " desktopMode ”.

Następnie za każdym razem, gdy jakiś efekt stylu dotyczy tylko urządzenia dotykowego lub tylko pulpitu, reguła css jest poprzedzona odpowiednią klasą:

.desktopMode .someClass:hover{ color: red }
.touchMode .mainDiv { width: 100%; margin: 0; /*etc.*/ }

Edycja : ta strategia oczywiście dodaje kilka dodatkowych znaków do twojego css, więc jeśli martwisz się o rozmiar css, możesz wyszukać definicje touchMode i desktopMode i umieścić je w różnych plikach, abyś mógł obsługiwać zoptymalizowany css dla każdego urządzenia rodzaj; albo możesz zmienić nazwy klas na coś znacznie krótszego przed przystąpieniem do produkcji.


2

Racja, ja jst miałem podobny problem, ale udało mi się go naprawić za pomocą zapytań o media i prostego CSS. Jestem pewien, że łamię tutaj pewne zasady, ale to działa na mnie.

Po prostu musiałem wziąć ogromną aplikację, którą ktoś stworzył, i sprawić, by była responsywna. Użyli jQueryUI i poprosili mnie, abym nie manipulował żadnym z ich jQuery, więc byłem ograniczony do używania samego CSS.

Kiedy nacisnąłem jeden z ich przycisków w trybie ekranu dotykowego, efekt najechania aktywowałby się na sekundę, zanim zadziałał przycisk. Oto jak to naprawiłem.

@media only screen and (max-width:1024px) {

       #buttonOne{
            height: 44px;
        }


        #buttonOne:hover{
            display:none;
        }
}   

2

W moim projekcie rozwiązaliśmy ten problem za pomocą https://www.npmjs.com/package/postcss-hover-prefix i https://modernizr.com/ Najpierw przetwarzamy wyjściowe pliki css za pomocą postcss-hover-prefix. Dodaje .no-touchdo wszystkich hoverreguł CSS .

const fs = require("fs");
const postcss = require("postcss");
const hoverPrfx = require("postcss-hover-prefix");

var css = fs.readFileSync(cssFileName, "utf8").toString();
postcss()
   .use(hoverPrfx("no-touch"))
   .process(css)
   .then((result) => {
      fs.writeFileSync(cssFileName, result);
   });

css

a.text-primary:hover {
  color: #62686d;
}

staje się

.no-touch a.text-primary:hover {
  color: #62686d;
}

W czasie wykonywania Modernizrautomatycznie dodaje klasy css do htmloznaczania w ten sposób

<html class="wpfe-full-height js flexbox flexboxlegacy canvas canvastext webgl 
  no-touch 
  geolocation postmessage websqldatabase indexeddb hashchange
  history draganddrop websockets rgba hsla multiplebgs backgroundsize borderimage
  borderradius boxshadow textshadow opacity cssanimations csscolumns cssgradients
  cssreflections csstransforms csstransforms3d csstransitions fontface
  generatedcontent video audio localstorage sessionstorage webworkers
  applicationcache svg inlinesvg smil svgclippaths websocketsbinary">

Takie przetwarzanie końcowe css plus Modernizr wyłącza kursor dla urządzeń dotykowych i włącza go dla innych. W rzeczywistości to podejście zostało zainspirowane Bootstrap 4, w jaki sposób rozwiązują ten sam problem: https://v4-alpha.getbootstrap.com/getting-started/browsers-devices/#sticky-hoverfocus-on-mobile


1

mouseLeaveZdarzenie można wywołać za każdym razem, gdy dotkniesz elementu na ekranie dotykowym. Oto rozwiązanie dla wszystkich <a>tagów:

function removeHover() {
    var anchors = document.getElementsByTagName('a');
    for(i=0; i<anchors.length; i++) {
        anchors[i].addEventListener('touchstart', function(e){
            $('a').mouseleave();
        }, false);
    }
}

JSHint mówi „nie twórz funkcji w pętli”.
NetOperator Wibby,

To hack. NIE jest to kod wielokrotnego użytku, który można uznać za dobrą praktykę. @NetOperatorWibby
Said Kholov

Cóż, wysyłanie kodu, którego nie można uznać za dobrą praktykę, nie jest zbyt pomocne. To tak, jakby założyć opatrunek na ranę noża.
NetOperator Wibby,

1

Znalazłem 2 rozwiązania tego problemu, co sugeruje, że wykrywasz kontakt z moderr lub czymś innym i ustawiasz klasę dotyku w elemencie html.

To jest dobre, ale niezbyt dobrze obsługiwane :

html.touch *:hover {
    all:unset!important;
}

Ale to ma bardzo dobre wsparcie :

html.touch *:hover {
    pointer-events: none !important;
}

Działa dla mnie bezbłędnie, sprawia, że ​​wszystkie efekty najechania na mysz będą wyglądać tak, jakbyś dotknął przycisku, który zaświeci się, ale nie zakończy się błędem, jak początkowy efekt najechania kursorem dla zdarzeń myszy.

Wykrywanie dotyku z urządzeń bezdotykowych Myślę, że modernizr wykonał najlepszą pracę:

https://github.com/Modernizr/Modernizr/blob/master/feature-detects/touchevents.js

EDYTOWAĆ

Znalazłem lepsze i prostsze rozwiązanie tego problemu

Jak ustalić, czy klient jest urządzeniem dotykowym


0

Pomocne może być zobaczenie CSS, ponieważ brzmi to raczej dziwnie. Ale w każdym razie, jeśli tak się dzieje i wszystko inne jest w porządku, możesz spróbować przenieść efekt najechania na javascript (możesz również użyć jquery). Po prostu połącz się ze zdarzeniem mouseover lub jeszcze lepiej mouseenter i zapal swój element, gdy zdarzenie zostanie uruchomione.

Sprawdź ostatni przykład tutaj: http://api.jquery.com/mouseover/ , możesz użyć czegoś podobnego do rejestrowania, gdy zdarzenie się uruchamia i stamtąd je zabrać!


Nic specjalnego w CSS; zobacz moją edycję. I już próbowałem mouseenter; nie ma kości. Stuknięcie przesuwa „niewidzialny kursor myszy”, więc uruchamia mouseenteri mousemove(i mouseleavekiedy stukniesz w inne miejsce).
Joe White

0

Jeśli jesteś zadowolony z używania JavaScript, możesz użyć Modernizr na swojej stronie. Po załadowaniu strony przeglądarka bez ekranu dotykowego będzie miała klasę „.no-touch” dodaną do tagu HTML, ale w przypadku przeglądarki z ekranem dotykowym tag HTML będzie miał klasę „.touch” dodaną do tagu HTML .

Następnie wystarczy sprawdzić, czy znacznik html ma klasę no-touch przed podjęciem decyzji o dodaniu mouseenter i mouseleave nasłuchujących.

if($('html').hasClass('no-touch')){
    $('.box').on("mouseenter", function(event){
            $(this).css('background-color','#0000ff')
    });
    $('.box').on("mouseleave", function(event){
            $(this).css('background-color','')
    });
}

W przypadku urządzenia z ekranem dotykowym zdarzenia nie będą miały słuchaczy, więc po dotknięciu nie pojawi się efekt najechania kursorem.


Kiedy można to zrobić za pomocą css, nie używaj javascript (jquery), to marnowanie mocy komputera
Simon Dragsbæk

1
Jeszcze prościej, w swoim CSS możesz zdefiniować oddzielne reguły dla .touchi .no-touch. Przepisanie odpowiedzi w CSS razem z Modernizerem html.no-touch .box:hover {background-color: "#0000ff"}i brak definiowania czegokolwiek html.touch .box:hoverpowinno załatwić sprawę, ponieważ OP stara się tylko unikać telefonów komórkowych :hover.
Walter Roman,

0

W projekcie, który robiłem niedawno, rozwiązałem ten problem za pomocą funkcji zdarzeń delegowanych w jQuery. Wyszukuje określone elementy za pomocą selektora jQuery i dodaje / usuwa klasę CSS do tych elementów, gdy wskaźnik myszy znajduje się nad elementem. Wydaje się, że działa dobrze, o ile mogłem to przetestować, w tym IE10 na notebooku obsługującym dotyk z systemem Windows 8.

$(document).ready(
    function()
    {
        // insert your own selector here: maybe '.hoverable'?
        var selector = 'button, .hotspot';

        $('body')
            .on('mouseover', selector, function(){ $(this).addClass('mouseover');    })
            .on('mouseout',  selector, function(){ $(this).removeClass('mouseover'); })
            .on('click',     selector, function(){ $(this).removeClass('mouseover'); });
    }
);

edycja: to rozwiązanie wymaga oczywiście zmiany CSS w celu usunięcia selektorów „: hover” i przemyślenia z wyprzedzeniem, które elementy mają być „hoverable”.

Jeśli masz na stronie bardzo dużo elementów (np. Kilka tysięcy), może się to trochę spowolnić, ponieważ to rozwiązanie wyłapuje zdarzenia trzech typów na wszystkich elementach na stronie, a następnie robi swoje, jeśli selektor pasuje. Nazwałem klasę CSS „mouseover” zamiast „hover”, ponieważ nie chciałem, aby czytający CSS czytali „: hover”, gdzie napisałem „.hover”.


0

Oto moje rozwiązanie: http://jsfiddle.net/agamemnus/g56aw709/ - kod poniżej.

Wszystko, co trzeba zrobić, to przekonwertować ich ": hover" na ".hover" ... to wszystko! Duża różnica między tym a resztą polega na tym, że będzie to działać również w przypadku selektorów elementów innych niż pojedyncze, takich jak .my_class > *:hover {.

handle_css_hover_effects ()

function handle_css_hover_effects (init) {
 var init = init || {}
 var handle_touch_events = init.handle_touch_events || true
 var handle_mouse_events = init.handle_mouse_events || true
 var hover_class         = init.hover_class         || "hover"
 var delay_preferences   = init.delay_preferences   || {touch: {add: 500, remove: 500}}
 function default_handler (curobj, input_type, op) {
  var hovered_element_selector = "*" + ((op == "add") ? ":" : ("." + hover_class))
  var hovered_elements = Array.prototype.slice.call(document.body.querySelectorAll(hovered_element_selector))
  var modified_list = []
  while (true) {
   if ((curobj == null) || (curobj == document.documentElement)) break
   if (hovered_elements.indexOf(curobj) != -1) modified_list.push (curobj)
   curobj = curobj.parentNode
  }
  function do_hover_change () {modified_list.forEach (function (curobj) {curobj.classList[op](hover_class)})}
  if ((!delay_preferences[input_type]) || (!delay_preferences[input_type][op])) {
   do_hover_change ()
  } else {
   setTimeout (do_hover_change, delay_preferences[input_type][op])
  }
 }

 if (handle_mouse_events) {
  document.body.addEventListener ('mouseover' , function (evt) {var curobj = evt.target; default_handler (curobj, "mouse", "add")})
  document.body.addEventListener ('mouseout'  , function (evt) {var curobj = evt.target; default_handler (curobj, "mouse", "remove")})
  document.body.addEventListener ('click'     , function (evt) {var curobj = evt.target; default_handler (curobj, "mouse", "remove")})
 }

 if (handle_touch_events) {
  document.body.addEventListener ('touchstart', function (evt) {var curobj = evt.target; default_handler (curobj, "touch", "add")})
  document.body.addEventListener ('touchend'  , function (evt) {var curobj = evt.target; default_handler (curobj, "touch", "remove")})
  document.body.addEventListener ('touchmove',  function (evt) {
   var curobj = evt.target
   var hovered_elements = Array.prototype.slice.call(document.body.querySelectorAll("*:hover"))
   var lastobj = null
   evt = evt.changedTouches[0]
   var elements_at_point = get_elements_at_point (evt.pageX, evt.pageY)
   // Get the last element that isn't at the current point but is still hovered over, and remove only its hover attribute.
   while (true) {
    if ((curobj == null) || (curobj == document.documentElement)) break
    if ((hovered_elements.indexOf(curobj) != -1) && (elements_at_point.indexOf(curobj) == -1)) lastobj = curobj
    curobj = curobj.parentNode
   }
   if (lastobj == null) return
   if ((!delay_preferences.touch) || (!delay_preferences.touch.remove)) {
    lastobj.classList.remove(hover_class)
   } else {
    setTimeout (function () {lastobj.classList.remove(hover_class)}, delay_preferences.touch.remove)
   }

   function get_elements_at_point (x, y) {
    var el_list = [], pe_list = []
    while (true) {
     var curobj = document.elementFromPoint(x, y)
     if ((curobj == null) || (curobj == document.documentElement)) break
     el_list.push (curobj); pe_list.push (curobj.style.pointerEvents)
     curobj.style.pointerEvents = "none"
    }
    el_list.forEach (function (current_element, i) {current_element.style.pointerEvents = pe_list[i]})
    return el_list
   }
  })
 }
}

0

Uwzględnij Modernizr na swojej stronie i zamiast tego ustaw stany najechania w następujący sposób:

html.no-touchevents .box:hover {
    background: blue;
}

0

Witaj osobie z przyszłości, prawdopodobnie chcesz skorzystać z zapytania pointeri / lub hovermedia query. handheldZapytania mediów została zaniechana.

/* device is using a mouse or similar */
@media (pointer: fine) {
  a:hover {
    background: red;
  }
}

-1

Wypróbuj to proste rozwiązanie jquery 2019, chociaż było ono już od jakiegoś czasu;

  1. dodaj tę wtyczkę do głowy:

    src="https://code.jquery.com/ui/1.12.0/jquery-ui.min.js"

  2. dodaj to do js:

    $("*").on("touchend", function(e) { $(this).focus(); }); //applies to all elements

  3. niektóre sugerowane warianty tego to:

    $(":input, :checkbox,").on("touchend", function(e) {(this).focus);}); //specify elements
    
    $("*").on("click, touchend", function(e) { $(this).focus(); });  //include click event`
    
    css: body { cursor: pointer; } //touch anywhere to end a focus`

Uwagi

  • umieść wtyczkę przed bootstrap.js, jeśli ma to zastosowanie, aby uniknąć wpływu na podpowiedzi
  • testowano tylko na iPhonie XR ios 12.1.12 i iPadzie 3 ios 9.3.5 przy użyciu przeglądarki Safari lub Chrome.

Bibliografia:

https://code.jquery.com/ui/

https://api.jquery.com/category/selectors/jquery-selector-extensions/

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.