Come faccio a simulare un passaggio del mouse con un browser abilitato al tocco?


120

Con un po 'di HTML come questo:

<p>Some Text</p>

Quindi alcuni CSS come questo:

p {
  color:black;
}

p:hover {
  color:red;
}

Come posso consentire a un tocco prolungato su un dispositivo abilitato al tocco di replicare il passaggio del mouse? Posso cambiare markup / usare JS ecc., Ma non riesco a pensare a un modo semplice per farlo.


Sto pensando in particolare a iPhone OS: è una demo dell'animazione CSS su cui per molti è facile usare il passaggio del mouse anziché i clic per iniziare.
Rich Bradshaw

Risposte:


172

OK, l'ho risolto! Si tratta di modificare leggermente il CSS e aggiungere un po 'di JS.

Usare jQuery per renderlo facile:

$(document).ready(function() {
    $('.hover').on('touchstart touchend', function(e) {
        e.preventDefault();
        $(this).toggleClass('hover_effect');
    });
});

In inglese: quando inizi o finisci un tocco, gira la classe hover_effect attiva o disattiva .

Quindi, nel tuo HTML, aggiungi un passaggio del mouse di classe a tutto ciò con cui vuoi che funzioni. Nel tuo CSS, sostituisci qualsiasi istanza di:

element:hover {
    rule:properties;
}

con

element:hover, element.hover_effect {
    rule:properties;
}

E solo per maggiore utilità, aggiungi anche questo al tuo CSS:

.hover {
-webkit-user-select: none;
-webkit-touch-callout: none;        
}

Per fermare il browser che ti chiede di copiare / salvare / selezionare l'immagine o qualsiasi altra cosa.

Facile!


Questo è fantastico. Ho diviso la funzione domready perché rovinerà le togglecose se l'utente tocca un elemento e lo trascina su un altro (ad esempio, se ha toccato l'elemento sbagliato e sta cercando di annullare il tocco)
Jacksonkr

Ho rimosso touchende preventDefault()nel mio sito web e funziona bene ma ora i menu non si chiudono automaticamente toccando fuori target.
Даниил Пронин

Vorrei anche qualche consiglio su come chiudere un tale menu quando l'utente tocca un altro punto o inizia a scorrere. Immagino che potrebbe esserci un altro touchstartascoltatore sul corpo (o simile) ma mi chiedevo se ci fosse un modo migliore. Grazie!
Darryl Young,

2
C'è comunque da ignorare un gesto di scorrimento? Questo fa esattamente quello che mi serve, ma ora non posso scorrere su e giù il contenuto che ha questo effetto.
spumeggiante il

1
Ho rimosso preventDefault poiché desidero che lo scorrimento sia disponibile ma grazie per i suggerimenti su touchstart e touchend! Dio manda questa è l'unica risposta che funziona in modo affidabile su tutti i browser.
Petraeus

54

Tutto quello che devi fare è associare touchstart a un genitore. Qualcosa di simile funzionerà:

$('body').on('touchstart', function() {});

Non è necessario eseguire alcuna operazione nella funzione, lasciarla vuota. Questo sarà sufficiente per ottenere il passaggio del mouse al tocco, quindi un tocco si comporta più come: hover e meno come: attivo. La magia di iOS.


2
Questa soluzione consente l'esecuzione del collegamento al secondo tocco?
samuelkobe

1
No, attiva ancora il clic al primo tocco. L'ho appena provato.
Jack

Ottima soluzione! Facile e veloce.
Hunter Turner,

41

Prova questo:

<script>
document.addEventListener("touchstart", function(){}, true);
</script>

E nel tuo CSS:

element:hover, element:active {
-webkit-tap-highlight-color: rgba(0,0,0,0);
-webkit-user-select: none;
-webkit-touch-callout: none /*only to disable context menu on long press*/
}

Con questo codice non hai bisogno di una classe .hover extra!


1
questo funziona per me .. alcune altre cose che potrebbero aiutarlo ancora di più sono invece di aggiungere javascript, fai così: <body ontouchstart = ""> quindi aggiungi un piccolo timer nel css: active event: tr: active {background-color : # 118aab; transizione: tutto lineare .2s; -webkit-tap-highlight-color: rgba (0,0,0,0); -webkit-user-select: nessuno; -webkit-touch-callout: nessuno}
Kozy

Ha funzionato per me. Grazie ... L'unica cosa - è un po 'in ritardo ... Voglio dire - dopo aver premuto, non si carica immediatamente.
Roman Losev

Usa fastclick.js per rimuovere il ritardo
Anselm

25

Per rispondere alla tua domanda principale: "Come faccio a simulare un passaggio del mouse con un browser abilitato al tocco?"

Consenti semplicemente di "fare clic" sull'elemento (toccando lo schermo), quindi attiva l' hoverevento utilizzando JavaScript.

var p = document.getElementsByTagName('p')[0];
p.onclick = function() {
 // Trigger the `hover` event on the paragraph
 p.onhover.call(p);
};

Dovrebbe funzionare, purché sia ​​presente un hoverevento sul dispositivo (anche se normalmente non viene utilizzato).

Aggiornamento: ho appena testato questa tecnica sul mio iPhone e sembra funzionare bene. Provalo qui: http://jsfiddle.net/mathias/YS7ft/show/light/

Se invece desideri utilizzare un "tocco lungo" per attivare il passaggio del mouse, puoi utilizzare lo snippet di codice sopra come punto di partenza e divertirti con timer e altro;)


Non sapevo di quel bit onhover.call (p), è piuttosto interessante. Non c'è nessun volo stazionario però ...
Rich Bradshaw

Lo hai testato con più elementi e tocco lungo? Significa che l'utente muove il dito sullo schermo e mostra uno stile al passaggio del mouse per ogni elemento?
Marcus

Sembra che se stai già utilizzando jQuery, potresti essere in grado di chiamare semplicemente l'evento hover con jQuery stesso, ad esempio: jQuery.hover (); Non sono sicuro che l'API lo supporti, però.
Kzqai

Ops, questo era un commento più applicabile al post sopra che utilizza effettivamente jQuery, mi dispiace.
Kzqai

Hai bisogno di uno script speciale o di chiamare la funzione? Per me funziona ma solo su una pagina e non so quale sia la differenza.
Richard Young,

13

Soluzione ulteriormente migliorata

All'inizio sono andato con l' approccio di Rich Bradshaw , ma poi sono iniziati i problemi. Facendo l'e.preventDefault () su 'TouchStart' evento, la pagina scorre più e, né la pressione prolungata è in grado di sparare il menu delle opzioni né doppio click zoom è in grado di finire l'esecuzione.

Una soluzione potrebbe essere scoprire quale evento viene chiamato e solo e.preventDefault () nell'ultimo , "touchend" . Poiché il "touchmove" di scorrimento viene prima di "touchend" , rimane come predefinito e anche il "clic" viene impedito poiché si trova dopo le parole nella catena di eventi applicata al dispositivo mobile, in questo modo:

// Binding to the '.static_parent' ensuring dynamic ajaxified content
$('.static_parent').on('touchstart touchend', '.link', function (e) {

    // If event is 'touchend' then...
    if (e.type == 'touchend') {
        // Ensuring we event prevent default in all major browsers
        e.preventDefault ? e.preventDefault() : e.returnValue = false;
    }

    // Add class responsible for :hover effect
    $(this).toggleClass('hover_effect');
});

Ma poi, quando viene visualizzato il menu delle opzioni, non attiva più "touchend" responsabile della disattivazione della classe e la prossima volta il comportamento del passaggio del mouse sarà il contrario, completamente confuso.

Una soluzione quindi sarebbe, ancora una volta, scoprire in modo condizionale in quale evento ci troviamo, o semplicemente eseguirne di separati, e utilizzare rispettivamente addClass () e removeClass () su 'touchstart' e 'touchend' , assicurandoti che inizi e finisca sempre per rispettivamente aggiungendo e rimuovendo invece di decidere in modo condizionale su di esso. Per finire vincoleremo anche la richiamata di rimozione al tipo di evento 'focusout' , rimanendo responsabili della cancellazione della classe hover di qualsiasi collegamento che potrebbe rimanere attiva e non essere mai più rivisitata, in questo modo:

$('.static_parent').on('touchstart', '.link', function (e) {
    $(this).addClass('hover_effect');
});

$('.static_parent').on('touchend focusout', '.link', function (e) {
    // Think double click zoom still fails here
    e.preventDefault ? e.preventDefault() : e.returnValue = false;
    $(this).removeClass('hover_effect');
});

Attenzione: Alcuni bug si verificano ancora nelle due soluzioni precedenti e, anche pensare (non testato), lo zoom con doppio clic non riesce ancora.

Soluzione Javascript ordinata e, si spera, priva di bug (non :))

Ora , per un secondo approccio, più pulito, ordinato e reattivo, usando semplicemente javascript (nessun mix tra classe .hover e pseudo: hover) e da dove potresti chiamare direttamente il tuo comportamento ajax sull'evento 'clic' universale (mobile e desktop) , Ho trovato una domanda abbastanza ben risolta da cui ho finalmente capito come potevo mescolare gli eventi di tocco e mouse insieme senza che diversi callback di eventi inevitabilmente cambiassero uno con l'altro nella catena degli eventi. Ecco come:

$('.static_parent').on('touchstart mouseenter', '.link', function (e) {
    $(this).addClass('hover_effect');
});

$('.static_parent').on('mouseleave touchmove click', '.link', function (e) {
    $(this).removeClass('hover_effect');

    // As it's the chain's last event we only prevent it from making HTTP request
    if (e.type == 'click') {
        e.preventDefault ? e.preventDefault() : e.returnValue = false;

        // Ajax behavior here!
    }
});

3

L' hovereffetto del mouse non può essere implementato nel dispositivo touch. Quando sono apparso con la stessa situazione in safari iosho usato:active in css per fare effetto.

vale a dire.

p:active {
  color:red;
}

Nel mio caso funziona. Può essere anche questo il caso che può essere utilizzato senza utilizzare javascript. Basta fare un tentativo.


2

Aggiungi questo codice e poi imposta la classe "tapHover" sugli elementi che vorresti lavorare in questo modo. La prima volta che tocchi un elemento, otterrai la pseudoclasse ": hover" e la classe "tapped". L'evento clic verrà impedito. La seconda volta che tocchi lo stesso elemento: verrà attivato l'evento clic.

// Activate only in devices with touch screen
if('ontouchstart' in window)
{
    // this will make touch event add hover pseudoclass
    document.addEventListener('touchstart', function(e) {}, true);

    // modify click event
    document.addEventListener('click', function(e) {
        // get .tapHover element under cursor
        var el = jQuery(e.target).hasClass('tapHover')
            ? jQuery(e.target)
            : jQuery(e.target).closest('.tapHover');

        if(!el.length)
            return;

        // remove tapped class from old ones
        jQuery('.tapHover.tapped').each(function() {
            if(this != el.get(0))
                jQuery(this).removeClass('tapped');
        });

        if(!el.hasClass('tapped'))
        {
            // this is the first tap
            el.addClass('tapped');
            e.preventDefault();
            return false;
        }
        else
        {
            // second tap
            return true;
        }
    }, true);
}
.box {
	float:		left;
	
	display:	inline-block;
	margin:		50px 0 0 50px;
	width:		100px;
	height:		100px;
	overflow:	hidden;
	
	font-size:	20px;
	
	border:		solid 1px black;
}
.box.tapHover {
	background:	yellow;
}
.box.tapped {
	border:		solid 3px red;
}
.box:hover {
	background:	red;
}
<div class="box" onclick="this.innerHTML = Math.random().toFixed(5)"></div>
<div class="box tapHover" onclick="this.innerHTML = Math.random().toFixed(5)"></div>
<div class="box tapHover" onclick="this.innerHTML = Math.random().toFixed(5)"></div>


1

Senza JS specifico per dispositivo (o meglio browser) sono abbastanza sicuro che tu sia sfortunato.

Modifica: pensavo volessi evitarlo finché non ho riletto la tua domanda. In caso di Mobile Safari puoi registrarti per ottenere tutti gli eventi touch simili a quello che puoi fare con gli UIView-s nativi. Non riesco a trovare la documentazione in questo momento, proverò a farlo.


1

Un modo per farlo sarebbe eseguire l'effetto hover quando inizia il tocco, quindi rimuovere l'effetto hover quando il tocco si sposta o finisce.

Questo è ciò che Apple ha da dire sulla gestione del tocco in generale, dal momento che parli di iPhone.


Il contenuto del collegamento è ancora pertinente ora?
Flavien Volken

1

Il mio gusto personale è di attribuire anche gli :hoverstili allo :focusstato, come:

p {
    color: red;
}

p:hover, p:focus {
    color: blue;
}

Quindi con il seguente HTML:

<p id="some-p-tag" tabindex="-1">WOOOO</p>

E il seguente JavaScript:

$("#some-p-tag").on("touchstart", function(e){
    e.preventDefault();
    var $elem = $(this);

    if($elem.is(":focus")) {
        //this can be registered as a "click" on a mobile device, as it's a double tap
        $elem.blur()
    }
    else {
        $elem.focus();
    }
});

1

Risolto 2019 - Passa il mouse sul tocco

Ora sembra meglio evitare di usare il passaggio del mouse del tutto con iOS o touch in generale. Il codice seguente applica il tuo css fintanto che il tocco viene mantenuto e senza altri flyout ios. Fai questo;

  1. Jquery aggiunge: $ ("p"). On ("touchstart", function (e) {$ (this) .focus (); e.preventDefault ();});

  2. CSS: sostituisci p: hover con p: focus e aggiungi p: active

Opzioni;

  • sostituire jquery p selector con qualsiasi classe ecc

  • per mantenere l'effetto, tieni anche p: hover e aggiungi body {cursor: ponter;} in modo che un tocco in qualsiasi punto lo termini

  • prova gli eventi click & mouseover e touchstart nello stesso codice (ma non testato)

  • rimuovere e.preventDefault (); per consentire agli utenti di utilizzare i flyout di iOS, ad esempio copy

Appunti

  • testato solo per elementi di testo, iOS può trattare gli input ecc. in modo diverso

  • testato solo su iphone XR ios 12.1.12 e ipad 3 ios 9.3.5, utilizzando Safari o Chrome.


0

Un mix di Javascript nativo e jQuery:

var gFireEvent = function (oElem,sEvent) 
{
 try {
 if( typeof sEvent == 'string' && o.isDOM( oElem ))
 {
  var b = !!(document.createEvent),
     evt = b?document.createEvent("HTMLEvents"):document.createEventObject();
  if( b )    
  {  evt.initEvent(sEvent, true, true ); 
    return !oElem.dispatchEvent(evt);
  }
  return oElem.fireEvent('on'+sEvent,evt);
 }
 } catch(e) {}
 return false;
};


// Next you can do is (bIsMob etc you have to determine yourself):

   if( <<< bIsMob || bIsTab || bisTouch >>> )
   {
     $(document).on('mousedown', function(e)
     {
       gFireEvent(e.target,'mouseover' );
     }).on('mouseup', function(e)
     {
       gFireEvent(e.target,'mouseout' );
     });
   }

1
mi dispiace essere pedante ma jquery è javacript
matpol

2
@matpol: jQuery è javascript ma javascript non è jQuery. Speciale per te aggiungo la parola "puro", puro javascript. Soddisfatto signore?
Codebeat

non puoi usare jquery senza usare javascript "puro". Faccio il punto solo perché alcune persone che frequentano SO non sembrano saperlo.
matpol

5
Un mix di Javascript nativo e jQuery, soddisfatto?
Codebeat

0

Soluzione più semplice che ho trovato: avevo alcuni tag <span> con: hover css rules in loro. Ho sostituito <a href = "javascript: void (0)"> e voilà. Gli stili di hover in iOS hanno iniziato a funzionare.


0

L'utilizzo può anche utilizzare CSS, aggiungere focus e attivo (per IE7 e precedenti) al collegamento nascosto. Esempio di un menu ul all'interno di un div con menu di classe:

.menu ul ul {display:none; position:absolute; left:100%; top:0; padding:0;}
.menu ul ul ul {display:none; position:absolute; top:0; left:100%;}
.menu ul ul a, .menu ul ul a:focus, .menu ul ul a:active { width:170px; padding:4px 4%; background:#e77776; color:#fff; margin-left:-15px; }
.menu ul li:hover > ul { display:block; }
.menu ul li ul li {margin:0;}

È in ritardo e non testato, dovrebbe funzionare ;-)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.