Le problème de survol de l'iPad / iPhone amène l'utilisateur à double-cliquer sur un lien

125

J'ai quelques sites Web que j'ai construits il y a des temps, qui utilisent des événements de souris jquery ... Je viens de recevoir un iPad et j'ai remarqué que tous les événements de survol de la souris sont traduits en clics ... donc par exemple, je dois faire deux clics au lieu d'un .. (le premier survol, que le clic réel)

existe-t-il une solution de contournement prête à résoudre ce problème? peut-être une commande jquery que je devrais avoir utilisée au lieu de mouseover / out etc. merci!

Francesco
la source
1
à quoi sont liés vos événements? par exemple, les événements onclick devraient fonctionner correctement ... onmouseover, onmouseout et le CSS: hover sont ceux qui sont un peu difficiles à gérer car il n'y a pas de "survol" disponible sur un écran tactile. Avez-vous un exemple de code?
scunliffe
Une chose que je vous suggère de faire est de repenser votre interface dans la mesure du possible. l'interaction sur l'ipad / iphone ne reflète pas exactement celle d'un PC, et c'est probablement une chose sage de donner à votre site Web l'impression qu'il a été écrit pour l'ipad / iphone / autres appareils tactiles avec des mécanismes multitouch similaires. Juste une pensée.
jer
Je suis d'accord avec "jer". C'est une question étrange, je ne pense pas que la solution ici soit une "solution de contournement" personnellement. Je pense que traduire un "survol de la souris" sur un navigateur de bureau en un "tapotement du doigt" sur un navigateur à écran tactile a du sens. Si vous êtes d'accord avec cette traduction, mais que vous voulez un robinet au lieu de deux, alors je ferais probablement une détection de fonctionnalité pour les événements iPad (par exemple "touchstart") et changerais vos gestionnaires d'événements. Peut-être extraire votre code dans un plugin jquery de type "toucher ou cliquer" qui se déclenche différemment en fonction des fonctionnalités, mais qui me semble spécifique à votre site Web / application.
Andy Atkinson
1
Je considère en fait cette traduction comme une fonctionnalité. Si vous aviez configuré des événements de survol, il devait y avoir un utilitaire pour les voir. Un simple tap révèle un élément survolé, un deuxième tap suit le lien «derrière» le survol.
Aaron

Réponses:

205

Je n'ai pas testé cela complètement, mais comme iOS déclenche des événements tactiles, cela pourrait fonctionner, en supposant que vous soyez dans un paramètre jQuery.

$('a').on('click touchend', function(e) {
    var el = $(this);
    var link = el.attr('href');
    window.location = link;
});

L'idée est que Mobile WebKit déclenche un touchendévénement à la fin d'un tap, donc nous écoutons cela, puis redirigeons le navigateur dès qu'un touchendévénement a été déclenché sur un lien.

cduruk
la source
17
Où est ma prime? : P
cduruk
2
Patience, Padwan. SO dit qu'il faut 24 heures pour entrer en vigueur.
Andrew Hedges
2
À partir de jQuery 1.7, .onest préférable à .live. Après avoir lu cette réponse, j'ai trouvé que changer mon code $('a').on('click touchend', function(e) {...})fonctionne parfaitement.
Blazemonger
23
Eh bien, cela résout le problème initial, mais en crée un nouveau: lorsque vous glissez dessus, vous cliquez dessus. Ce n'est pas une solution.
luksak
9
Cela a ses défauts. Si vous cliquez sur un lien, target="_blank"il s'ouvrira dans la même fenêtre ET dans une nouvelle fenêtre.
rybo111
37

Votre question n'est pas tout à fait claire, mais si vous souhaitez simplement éliminer le double clic, tout en conservant l'effet de survol pour la souris, mon conseil est de:

  • Ajoutez des effets de survol sur touchstartet mouseenter.
  • Retirer les effets hover sur mouseleave, touchmoveet click.

Contexte

Afin de simuler une souris, les navigateurs tels que Webkit mobile déclenchent les événements suivants si un utilisateur touche et relâche un doigt sur l'écran tactile (comme l'iPad) (source: Touch And Mouse sur html5rocks.com):

  1. touchstart
  2. touchmove
  3. touchend
  4. Retard de 300 ms, où le navigateur s'assure qu'il s'agit d'un simple tap, pas d'un double tap
  5. mouseover
  6. mouseenter
    • Remarque : Si un événement mouseover, mouseenterou mousemovemodifie le contenu de la page, les événements suivants ne sont jamais déclenchés.
  7. mousemove
  8. mousedown
  9. mouseup
  10. click

Il ne semble pas possible de dire simplement au navigateur Web de sauter les événements de la souris.

Pire encore, si un événement mouseover modifie le contenu de la page, l'événement click n'est jamais déclenché, comme expliqué dans Safari Web Content Guide - Handling Events , en particulier la figure 6.4 dans One-Finger Events . Ce qu'est exactement un «changement de contenu» dépendra du navigateur et de la version. J'ai constaté que pour iOS 7.0, un changement de couleur d'arrière-plan n'est pas (ou plus?) Un changement de contenu.

Solution expliquée

Récapituler:

  • Ajoutez des effets de survol sur touchstartet mouseenter.
  • Retirer les effets hover sur mouseleave, touchmoveet click.

Notez qu'il n'y a aucune action sur touchend!

Cela fonctionne clairement pour les événements de souris: mouseenteret mouseleave(versions légèrement améliorées de mouseoveret mouseout) sont déclenchés, et ajoutez et supprimez le survol.

Si l'utilisateur click un lien, l'effet de survol est également supprimé. Cela garantit qu'il est supprimé si l'utilisateur appuie sur le bouton de retour dans le navigateur Web.

Cela fonctionne également pour les événements tactiles: sur touchstartl'effet de survol est ajouté. Il n'est "" pas "supprimé le touchend. Il est ajouté à nouveau mouseenter, et comme cela n'entraîne aucun changement de contenu (il a déjà été ajouté), l' clickévénement est également déclenché et le lien est suivi sans que l'utilisateur ait besoin de cliquer à nouveau!

Le délai de 300 ms qu'un navigateur a entre un touchstartévénement et clickest effectivement utilisé à bon escient car l'effet de survol sera affiché pendant ce court laps de temps.

Si l'utilisateur décide d'annuler le clic, un mouvement du doigt le fera comme d'habitude. Normalement, c'est un problème car aucun mouseleaveévénement n'est déclenché et l'effet de survol reste en place. Heureusement, cela peut facilement être résolu en supprimant l'effet de survol touchmove.

C'est tout!

Notez qu'il est possible de supprimer le délai de 300 ms, par exemple à l'aide de la bibliothèque FastClick , mais cela est hors de portée pour cette question.

Solutions alternatives

J'ai trouvé les problèmes suivants avec les alternatives suivantes:

  • détection du navigateur: extrêmement sujet aux erreurs. Suppose qu'un appareil dispose d'une souris ou d'un écran tactile, alors qu'une combinaison des deux deviendra de plus en plus courante lorsque les écrans tactiles proliféreront.
  • Détection de média CSS: la seule solution CSS que je connaisse. Toujours sujet aux erreurs, et suppose toujours qu'un périphérique a la souris ou le tactile, alors que les deux sont possibles.
  • Émuler l'événement de clic dans touchend: Cela suivra incorrectement le lien, même si l'utilisateur voulait uniquement faire défiler ou zoomer, sans l'intention de cliquer réellement sur le lien.
  • Utilisez une variable pour supprimer les événements de souris: Ceci définit une variable dans touchendqui est utilisée comme condition if dans les événements de souris suivants pour empêcher les changements d'état à ce moment-là. La variable est réinitialisée dans l'événement de clic. C'est une solution décente si vous ne voulez vraiment pas d'effet de survol sur les interfaces tactiles. Malheureusement, cela ne fonctionne pas si a touchendest déclenché pour une autre raison et qu'aucun événement de clic n'est déclenché (par exemple, l'utilisateur a fait défiler ou zoomé), et tente ensuite de suivre le lien avec une souris (c'est-à-dire sur un appareil avec à la fois une souris et une interface tactile ).

Lectures complémentaires

Voir également Problème de double-clic sur iPad / iPhone et Désactiver les effets de survol sur les navigateurs mobiles .

MacFreek
la source
2
semble être la meilleure explication pour ceux qui veulent une solution plus précise du problème. Thanx
Antiplayer
Un merci spécial pour les informations sur la couleur de fond pour> iOS7. J'ai passé du temps à essayer de comprendre quand cela a commencé à fonctionner.
staff du
20

Il semble qu'il existe une solution CSS après tout. La raison pour laquelle Safari attend une deuxième touche est à cause de l'image d'arrière-plan (ou des éléments) que vous attribuez habituellement à l'événement: hover. S'il n'y en a pas à afficher, vous n'aurez aucun problème. La solution est de cibler la plateforme iOS avec un fichier CSS secondaire (ou un style dans le cas d'une approche JS) qui se substitue: survolez l'arrière-plan pour hériter par exemple et gardez cachés les éléments que vous alliez afficher au survol de la souris:

Voici un exemple de CSS et HTML - un bloc de produit avec une étiquette étoilée au survol de la souris:

HTML:

<a href="#" class="s"><span class="s-star"></span>Some text here</a>

CSS:

.s {
   background: url(some-image.png) no-repeat 0 0;

}
.s:hover {
   background: url(some-image-r.png) no-repeat 0 0;
}

.s-star {
   background: url(star.png) no-repeat 0 0;
   height: 56px;
   position: absolute;
   width: 72px;
   display:none;
}

.s:hover .s-star {
   display:block;
}

Solution (CSS secondaire):

/* CSS */
/* Keep hovers the same or hidden */
.s:hover {
   background:inherit;
}
.s:hover .s-star {
   display:none;
}
Pavel Bogatinov
la source
Cette réponse est orientée vers les images d'arrière-plan, mais avez-vous une solution pour de simples changements d'opacité? Cette solution ne fonctionne pas pour cela.
Ian S
5

Pas besoin de faire trop compliqué.

$('a').on('touchend', function() {
    $(this).click();
});
Jsonras
la source
5

Ce qui a fonctionné pour moi, c'est ce que d'autres ici ont déjà dit:

Ne pas afficher / masquer les éléments au survol ou à la souris (ce qui est l'événement dans mon cas).

Voici ce que dit Apple ( https://developer.apple.com/library/content/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html ):

Un élément cliquable est un lien, un élément de formulaire, une zone de carte d'image ou tout autre élément avec des gestionnaires mousemove, mousedown, mouseup ou onclick

Si l'utilisateur appuie sur un élément cliquable, les événements arrivent dans cet ordre: mouseover, mousemove, mousedown, mouseup et click. De plus, si le contenu de la page change lors de l'événement mousemove, aucun événement ultérieur de la séquence n'est envoyé. Ce comportement permet à l'utilisateur d'appuyer sur le nouveau contenu.

Ainsi, vous pouvez utiliser la solution de @ woop: détecter le userAgent, vérifier s'il s'agit d'un appareil iOS, puis lier l'événement. J'ai fini par utiliser cette technique car elle répond à mes besoins et il est plus logique de ne pas lier les événements de survol lorsque vous ne le souhaitez pas.

Mais ... si vous ne voulez pas jouer avec userAgents et toujours masquer / afficher des éléments sur hover / mousemove, j'ai découvert que vous pouvez le faire en utilisant du javascript natif, comme ceci:

$("body").on("mouseover", function() {
       document.getElementsByTagName("my-class")[0].style.display = 'block'; //show element
       document.querySelector(".my-selector div").style.display = 'none'; // hide element
});

Cela fonctionnera sur la version Desktop et ne fera rien sur la version mobile.

Et pour un peu plus de compatibilité ...

$("body").on("mouseover", function() {
   if (document.getElementsByTagName && document.querySelector) { // check compatibility
       document.getElementsByTagName("my-class")[0].style.display = 'block'; //show element
       document.querySelector(".my-selector div").style.display = 'none'; // hide element
    } else {
        $(".my-class").show();
        $(".my-selector div").hide();
    }
});
Adauto
la source
1
Ce bit "si le contenu de la page change lors de l'événement mousemove, aucun événement ultérieur de la séquence n'est envoyé" l'a vraiment fait pour moi. J'avais une page où les liens d'en-tête nécessiteraient un double tap où les boutons dans le contenu (avec toutes les transitions css3 heureuses sur em) ne nécessiteraient qu'un seul tap. Apparaissait que les liens d'en-tête avaient un pseudo-élément qui passait d'opacité: 0 à opacité: 1 lors du survol. La suppression de cet effet a immédiatement résolu le problème et j'ai trouvé une solution de contournement CSS pour toujours obtenir les looks que je voulais.
Fake Haak
3

La solution de cduruk a été assez efficace, mais a causé des problèmes sur quelques parties de mon site. Parce que j'utilisais déjà jQuery pour ajouter la classe de survol CSS, la solution la plus simple était de simplement ne pas ajouter la classe de survol CSS sur les appareils mobiles (ou plus précisément, de l'ajouter UNIQUEMENT lorsque PAS sur un appareil mobile).

Voici l'idée générale:

var device = navigator.userAgent.toLowerCase();
var ios = device.match(/(iphone|ipod|ipad)/);

if (!(ios)) {
    $(".portfolio-style").hover(
        function(){
            $(this).stop().animate({opacity: 1}, 100);
            $(this).addClass("portfolio-red-text");
        },
        function(){
            $(this).stop().animate({opacity: 0.85}, 100);
            $(this).removeClass("portfolio-red-text");
        }
    );
}

* code réduit à titre illustratif

woop
la source
1
C'est clairement la réponse. Les autres «solutions» ne résolvent pas le problème. Le safari iOS est clairement imparfait en pensant que nous voulons d'abord survoler. D'autres systèmes d'exploitation ont des fonctionnalités de survol réelles lorsque vous survolez un élément.
Joshua Pack
C'était la seule chose qui fonctionnait pour moi. Merci beaucoup!
tx291
2

Je pense qu'il serait sage d'essayer mouseenterà la place de mouseover. C'est ce qui est utilisé en interne lors de la liaison .hover(fn,fn)et c'est généralement ce que vous voulez.

Paul irlandais
la source
1

J'ai eu les problèmes suivants avec les solutions existantes et j'ai trouvé quelque chose qui semble les résoudre toutes. Cela suppose que vous visez quelque chose de multi-navigateur, multi-appareil et que vous ne voulez pas renifler l'appareil.

Les problèmes que cela résout

En utilisant juste touchstartou touchend:

  • Provoque le déclenchement de l'événement lorsque des personnes essaient de faire défiler le contenu et ont juste eu le doigt sur cet élément lorsqu'elles commencent à balayer - ce qui déclenche l'action de manière inattendue.
  • Peut provoquer le déclenchement de l'événement sur une pression longue , similaire à un clic droit sur le bureau. Par exemple, si votre événement de clic va à l'URL X et que l'utilisateur appuie longuement pour ouvrir X dans un nouvel onglet, l'utilisateur sera confus pour trouver X ouvert dans les deux onglets. Sur certains navigateurs (par exemple l'iPhone), cela peut même empêcher le menu de pression longue d'apparaître.

Déclenchement des mouseoverévénements sur touchstartet mouseoutsur touchmovea des conséquences moins graves, mais n'interfère avec le comportement du navigateur habituel, par exemple:

  • Un appui long déclencherait un survol de la souris qui ne se termine jamais.
  • De nombreux navigateurs Android traitent l'emplacement du doigt touchstartcomme un mouseover, qui est mouseoutédité sur le suivant touchstart. Une façon de voir le contenu de la souris dans Android est donc de toucher la zone d'intérêt et de bouger votre doigt, en faisant légèrement défiler la page. Traiter touchmovecomme mouseoutcasse cela.

La solution

En théorie, vous pouvez simplement ajouter un drapeau avec touchmove, mais les iPhones déclenchent le touchmove même s'il n'y a pas de mouvement. En théorie, vous pouvez simplement comparer le touchstartet touchendévénement pageXet pageY mais sur iPhone, il n'y a pas touchend pageXoupageY .

Donc, malheureusement, pour couvrir toutes les bases, cela finit par être un peu plus compliqué.

$el.on('touchstart', function(e){
    $el.data('tstartE', e);
    if(event.originalEvent.targetTouches){
        // store values, not reference, since touch obj will change
        var touch = e.originalEvent.targetTouches[0];
        $el.data('tstartT',{ clientX: touch.clientX, clientY: touch.clientY } );
    }
});
$el.on('touchmove', function(e){
    if(event.originalEvent.targetTouches){
        $el.data('tstartM', event.originalEvent.targetTouches[0]);
    }
});

$el.on('click touchend', function(e){
    var oldE = $el.data('tstartE');
    if( oldE && oldE.timeStamp + 1000 < e.timeStamp ) {
        $el.data('tstartE',false);
        return;
    }
    if( $el.data('iosTouchM') && $el.data('tstartT') ){
        var start = $el.data('tstartT'), end = $el.data('tstartM');
        if( start.clientX != end.clientX || start.clientY != end.clientY ){
            $el.data('tstartT', false);
            $el.data('tstartM', false);
            $el.data('tstartE',false);
            return;
        }
    }
    $el.data('tstartE',false);

En théorie, il existe des moyens d'obtenir l'heure exacte utilisée pour une impression longue au lieu d'utiliser simplement 1000 comme approximation, mais en pratique, ce n'est pas si simple et il est préférable d'utiliser un proxy raisonnable .

user56reinstatemonica8
la source
1

La réponse de MacFreak m'a été extrêmement utile. Voici un code pratique au cas où cela vous aiderait.

PROBLÈME - appliquer touchend signifie que chaque fois que vous faites défiler votre doigt sur un élément, il répond comme si vous l'aviez appuyé, même si vous essayiez simplement de faire défiler.

Je crée un effet avec jQuery qui fait fondre une ligne sous certains boutons pour "mettre en évidence" le bouton survolé. Je ne veux pas que cela signifie que vous devez appuyer deux fois sur le bouton des appareils tactiles pour suivre le lien.

Voici les boutons:

<a class="menu_button" href="#">
    <div class="menu_underline"></div>
</a>

Je veux que le div "menu_underline" disparaisse au passage de la souris et disparaisse au passage de la souris. MAIS je veux que les appareils tactiles puissent suivre le lien en un seul clic, pas deux.

SOLUTION - Voici le jQuery pour le faire fonctionner:

//Mouse Enter
$('.menu_button').bind('touchstart mouseenter', function(){
    $(this).find(".menu_underline").fadeIn();
});

//Mouse Out   
$('.menu_button').bind('mouseleave touchmove click', function(){
    $(this).find(".menu_underline").fadeOut();
});

Merci beaucoup pour votre aide sur ce MacFreak.

Mad Dog Cadogen
la source
1

Je viens de découvrir que cela fonctionne si vous ajoutez un auditeur vide, ne me demandez pas pourquoi, mais je l'ai testé sur iPhone et iPad avec iOS 9.3.2 et cela a bien fonctionné.

if(/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream){
    var elements = document.getElementsByTagName('a');
    for(var i = 0; i < elements.length; i++){
        elements[i].addEventListener('touchend',function(){});
    }
}
baguette de freek van der
la source
0

J'ai eu le même problème mais pas sur un appareil tactile. L'événement se déclenche à chaque fois que vous cliquez. Il y a quelque chose à propos de la file d'attente d'événements.

Cependant, ma solution était la suivante: sur l'événement de clic (ou toucher?) Vous définissez une minuterie. Si le lien est à nouveau cliqué dans X ms, vous renvoyez simplement false.

Pour définir la minuterie par élément, vous pouvez utiliser $.data().

Cela peut également résoudre le problème @Ferdy décrit ci-dessus.

Ionuț Staicu
la source
Pouvez-vous poster à quoi ressemble ce code? J'ai ce problème d'événement de clic déclenché deux fois.
fantaisie
0

Si vous utilisez Modernizr, il est très facile d'utiliser Modernizr.touch comme mentionné précédemment.

Cependant, je préfère utiliser une combinaison de tests Modernizr.touch et d'agent utilisateur, juste pour être sûr.

var deviceAgent = navigator.userAgent.toLowerCase();

var isTouchDevice = Modernizr.touch || 
(deviceAgent.match(/(iphone|ipod|ipad)/) ||
deviceAgent.match(/(android)/)  || 
deviceAgent.match(/(iemobile)/) || 
deviceAgent.match(/iphone/i) || 
deviceAgent.match(/ipad/i) || 
deviceAgent.match(/ipod/i) || 
deviceAgent.match(/blackberry/i) || 
deviceAgent.match(/bada/i));

function Tipsy(element, options) {
    this.$element = $(element);
    this.options = options;
    this.enabled = !isTouchDevice;
    this.fixTitle();
};

Si vous n'utilisez pas Modernizr, vous pouvez simplement remplacer le Modernizr.touch fonction ci-dessus par('ontouchstart' in document.documentElement)

Notez également que le test de l'agent utilisateur iemobile vous donnera une plus large gamme d'appareils mobiles Microsoft détectés que Windows Phone.

Peter-Pan
la source
0

Vous pouvez utiliser click touchend,

exemple:

$('a').on('click touchend', function() {
    var linkToAffect = $(this);
    var linkToAffectHref = linkToAffect.attr('href');
    window.location = linkToAffectHref;
});

L'exemple ci-dessus affectera tous les liens sur les appareils tactiles.

Si vous souhaitez cibler uniquement des liens spécifiques, vous pouvez le faire en leur définissant une classe, c'est-à-dire:

HTML:

<a href="example.html" class="prevent-extra-click">Prevent extra click on touch device</a>

Jquery:

$('a.prevent-extra-click').on('click touchend', function() {
    var linkToAffect = $(this);
    var linkToAffectHref = linkToAffect.attr('href');
    window.location = linkToAffectHref;
});

À votre santé,

Jeroen

Jeroen W
la source
0

J'ai rencontré une situation similaire où j'avais des événements liés aux états mouseenter / mouseleave / click d'un élément, mais sur un iPhone, l'utilisateur devait double-cliquer sur l'élément pour déclencher d'abord l'événement mouseenter, puis à nouveau pour déclencher l'événement click .

J'ai résolu cela en utilisant une méthode similaire à celle ci-dessus, mais j'ai utilisé le plugin jQuery $ .browser (pour jQuery 1.9>) et ajouté un événement .trigger à l'événement de liaison mouseenter, comme suit:

// mouseenter event
$('.element').on( "mouseenter", function() {
    // insert mouseenter events below

    // double click fix for iOS and mouseenter events
    if ($.browser.iphone || $.browser.ipad) $(this).trigger('click');
});
// mouseleave event
$('.element').on( "mouseleave", function() { 
    // insert mouseout events below
});
// onclick event
$('.element').on( "click", function() {
    // insert click events below
});

Le .trigger évite d'avoir à double-cliquer sur l'élément en déclenchant le gestionnaire d'événements .click lors de la saisie de la souris (ou du clic initial) de l'élément lorsqu'il est visualisé sur iPhone ou iPad. Ce n'est peut-être pas la solution la plus élégante, mais cela fonctionne très bien dans mon cas et utilise un plugin que j'avais déjà en place, et m'a obligé à ajouter une seule ligne de code pour que mes événements existants fonctionnent sous ces appareils.

Vous pouvez obtenir le plugin jQuery $ .browser ici: https://github.com/gabceb/jquery-browser-plugin

oui-ja
la source
0

Juste une amélioration pour éviter la redirection lorsque vous faites glisser votre doigt sur un lien par erreur.

// tablet "one touch (click)" X "hover" > link redirection
$('a').on('touchmove touchend', function(e) {

    // if touchmove>touchend, set the data() for this element to true. then leave touchmove & let touchend fail(data=true) redirection
    if (e.type == 'touchmove') {
        $.data(this, "touchmove_cancel_redirection", true );
        return;
    }

    // if it's a simple touchend, data() for this element doesn't exist.
    if (e.type == 'touchend' && !$.data(this, "touchmove_cancel_redirection")) {
        var el = $(this);
        var link = el.attr('href');
        window.location = link;
    }

    // if touchmove>touchend, to be redirected on a future simple touchend for this element
    $.data(this, "touchmove_cancel_redirection", false );
});
Lenor
la source
0

Avec l'inspiration de MacFreak, j'ai mis en place quelque chose qui fonctionne pour moi.

Cette méthode js empêche le survol de coller sur un iPad et empêche le clic de s'enregistrer en deux clics dans certains cas. En CSS, si vous avez des classes: hover psudo dans votre css, changez-les en .hover Par exemple .some-class: hover en .some-class.hover

Testez ce code sur un iPad pour voir comment les méthodes hover css et js se comportent différemment (en effet hover uniquement). Le bouton CSS n'a pas d'alerte de clic sophistiquée. http://jsfiddle.net/bensontrent/ctgr6stm/

function clicker(id, doStuff) {
  id.on('touchstart', function(e) {
    id.addClass('hover');
  }).on('touchmove', function(e) {
    id.removeClass('hover');
  }).mouseenter(function(e) {
    id.addClass('hover');
  }).mouseleave(function(e) {
    id.removeClass('hover');
  }).click(function(e) {
    id.removeClass('hover');
    //It's clicked. Do Something
    doStuff(id);
  });
}

function doStuff(id) {
  //Do Stuff
  $('#clicked-alert').fadeIn(function() {
    $(this).fadeOut();
  });
}
clicker($('#unique-id'), doStuff);
button {
  display: block;
  margin: 20px;
  padding: 10px;
  -webkit-appearance: none;
  touch-action: manipulation;
}
.hover {
  background: yellow;
}
.btn:active {
  background: red;
}
.cssonly:hover {
  background: yellow;
}
.cssonly:active {
  background: red;
}
#clicked-alert {
  display: none;
}
<button id="unique-id" class="btn">JS Hover for Mobile devices<span id="clicked-alert"> Clicked</span>

</button>
<button class="cssonly">CSS Only Button</button>
<br>This js method prevents hover from sticking on an ipad, and prevents the click registering as two clicks. In CSS, if you have any :hover in your css, change them to .hover For example .some-class:hover to .some-class.hover

Benson
la source
0

Pour que les liens fonctionnent sans interrompre le défilement tactile, j'ai résolu ce problème avec l'événement "tap" de jQuery Mobile:

    $('a').not('nav.navbar a').on("tap", function () {
        var link = $(this).attr('href');
        if (typeof link !== 'undefined') {
            window.location = link;
        }
    });
les orignaux
la source
0

Je suis trop tard, je sais, mais c'est l'une des solutions de contournement les plus simples que j'ai trouvées:

    $('body').on('touchstart','*',function(){   //listen to touch
        var jQueryElement=$(this);  
        var element = jQueryElement.get(0); // find tapped HTML element
        if(!element.click){
            var eventObj = document.createEvent('MouseEvents');
            eventObj.initEvent('click',true,true);
            element.dispatchEvent(eventObj);
        }
    });

Cela ne fonctionne pas seulement pour les liens (balises d'ancrage) mais aussi pour d'autres éléments. J'espère que cela t'aides.

writeToBhuwan
la source
0

Ce court extrait semble fonctionner. Déclenchez l'événement de clic lorsque le lien est tapé:

  $('a').on('touchstart', function() {
    $(this).trigger('click');
  });
Développer Flo
la source
0

Aucune de l'autre réponse ne fonctionne pour moi. Mon application a beaucoup d'écouteurs d'événements, de propres cases à cocher et de liens qui ont un auditeur et des liens sans auditeur.

J'utilise ceci:

var selector = "label, a, button";
var timer;
var startX;
var startY;
$(document).on("click", selector, function (e) {
    if ($(this).data("touched") === true) {
        e.stopImmediatePropagation();
        return false;
    }
    return;
}).on("touchend", selector, function (e) {
    if (Math.abs(startX - e.originalEvent.changedTouches[0].screenX) > 10 || Math.abs(startY - e.originalEvent.changedTouches[0].screenY) > 10)
        // user action is not a tap
        return;
    var $this = $(this);
    // Visit: http://stackoverflow.com/questions/1694595/can-i-call-jquery-click-to-follow-an-a-link-if-i-havent-bound-an-event-hand/12801548#12801548
    this.click();
    // prevents double click
    $this.data("touched", true);
    if (timer)
        clearTimeout(timer);
    setTimeout(function () {
        $this.data("touched", false);
    }, 400);
    e.stopImmediatePropagation();
    return false;
}).on("touchstart", function (e) {
    startX = e.originalEvent.changedTouches[0].screenX;
    startY = e.originalEvent.changedTouches[0].screenY;
});
Magu
la source
0

Cela fonctionne pour moi lorsque vous avez jquery ui dropdown

if (navigator.userAgent.match(/(iPod|iPhone|iPad)/)) {
      $('.ui-autocomplete').off('menufocus hover mouseover');
}
Makubex
la source
0

Évitez de changer le style «d'affichage» à l'intérieur de l'événement css hover. J'avais "display: block" en état de survol. Après avoir retiré ios est allé sur les lignes en un seul clic. Au fait, il semble que les dernières mises à jour IOS aient corrigé cette "fonctionnalité"

Hellbyte
la source
0

Le moyen le plus simple de résoudre le double-clic sur l'iPad consiste à envelopper votre css pour un effet de survol dans une requête multimédia @media (pointer: fine):

@media (pointer: fine) {
  a span {
    display: none;
  }
  a:hover span {
    display: inline-block;
  }
}

Le CSS enveloppé dans cette requête multimédia ne s'appliquera que sur le bureau.

L'explication de cette solution est ici https://css-tricks.com/annoying-mobile-double-tap-link-issue/

Galina
la source
-1

Vous pouvez vérifier navigator.userAgentcomme ceci:

if(!navigator.userAgent.match(/iPhone/i) || !navigator.userAgent.match(/iPad/i)) {
    //bind your mouseovers...
}

mais vous devrez vérifier les mûres, les droïdes et les autres appareils à écran tactile. Vous pouvez également lier les survols de souris uniquement si userAgent contient Mozilla, IE, Webkit ou Opera, mais vous devez toujours rechercher certains appareils car le Droid, par exemple, signale sa chaîne userAgent comme:

Mozilla/5.0 (Linux; U; Android 2.0.1; en-us; Droid Build/ESD56) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17

La chaîne de l'iPhone est similaire. Si vous recherchez uniquement iPhone, iPod, iPad, Android et Blackberry, vous pourriez obtenir la majorité des ordinateurs de poche, mais pas tous.

jasongetsdown
la source
Je pense que, pour le moment, pour ne pas devenir fou, la meilleure chose à faire pourrait être juste un script qui saute les événements de survol ... donc je suppose que la première réponse était bonne ... et oui vous avez raison ... je devrais pensez à tous les autres appareils ... j'aurais aimé que Jquery ou un plugin ait ce genre de fonction de détection ..!
Francesco
wurfl.sourceforge.net Cela pourrait être votre réponse. C'est une base de données d'appareils sans fil. Ce ne sera pas aussi simple qu'un plugin jQuery, mais vous pouvez toujours en écrire un! Il y a aussi tera-wurfl.com qui utilise une base de données plutôt qu'un fichier xml. Je n'ai pas beaucoup creusé, mais il existe peut-être une version hébergée, vous n'avez donc pas à vous soucier de garder votre fichier wurfl ou votre base de données tera-wurfl à jour.
jasongetsdown
1
Est-ce que je manque quelque chose ou la question n'était PAS de détecter les iPad, mais de contourner un comportement spécifique sur les iPad?
Andrew Hedges
5
UA reniflant? How 90's: P
Macha
-1

Faites simplement une requête multimédia CSS qui exclut les tablettes et les appareils mobiles et placez le survol. Vous n'avez pas vraiment besoin de jQuery ou de JavaScript pour cela.

@media screen and (min-device-width:1024px) {
    your-element:hover {
        /* Do whatever here */
    }
}

Et assurez-vous de l'ajouter à votre tête HTML pour vous assurer qu'il calcule avec les pixels réels et non la résolution.

<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
Dalibor
la source