web-dev-qa-db-fra.com

Champ de texte Autofocus Mobile Safari

Dans Mobile Safari, je ne peux pas me concentrer sur un champ de texte après avoir défini un délai. Je joins un exemple de code présentant le problème . Si, en cliquant sur le bouton, vous déclenchez .focus (), tout fonctionne comme prévu. Si vous bloquez le focus sur un rappel, comme la fonction setTimeout, il échoue UNIQUEMENT dans le safari mobile. Dans tous les autres navigateurs, il y a un délai, puis le focus se produit.

De manière confuse, l’événement "focusin" est déclenché, même dans un safari mobile. Ceci (et des commentaires similaires dans SO) me fait penser que c'est un bug de safari mobile. Toute orientation sera acceptée.

J'ai testé dans l'émulateur et sur l'iPhone 3GS/4 iOS4.

Exemple HTML:

<!DOCTYPE html> 
  <html lang='en'> 
    <head> 
      <title>Autofocus tests</title> 
      <meta content='width=device-width, initial-scale=1.0, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0' name='viewport'> 
      <meta content='yes' name='Apple-mobile-web-app-capable'> 
    </head> 
    <body>
      <h1> 
        Show keyboard without user focus and select text:
      </h1> 
      <p> 
        <button id='focus-test-button'> 
          Should focus on input when you click me after .5 second
        </button> 
        <input id='focus-test-input' type='number' value='20'> 
      </p> 
      <script type="text/javascript"> 
        //<![CDATA[
        var button = document.getElementById('focus-test-button');
        var input  = document.getElementById('focus-test-input');

        input.addEventListener('focusin', function(event) {
          console.log('focus');
          console.log(event);
        });

        button.addEventListener('click', function() {
          // *** If triggered immediately - functionality occurs as expected
          // input.focus();
          // *** If called by callback - triggers the focusin event, but does not bring up keyboard or cursor
          var t = setTimeout("input.focus();",500);
        });
        //]]>
      </script>
    </body>
  </html>

~ Questions similaires ~ SO:

51
boymc

Je pense que c'est une fonctionnalité de Safari mobile plutôt qu'un bug. Dans notre travail sur FastClick , mes collègues et moi avons constaté qu'iOS ne permet de déclencher le focus que sur d'autres éléments, à partir d'une fonction, si la première fonction de la pile d'appels a été déclenchée par un événement non programmatique. Dans votre cas, l’appel de setTimeout démarre une nouvelle pile d’appels et le mécanisme de sécurité s’active pour vous empêcher de définir le focus sur l’entrée.

N'oubliez pas que sur iOS, le focus est défini sur un élément d'entrée pour que le clavier s'affiche. Ainsi, comme le fait Google, il serait extrêmement gênant d'utiliser toutes les pages Web qui se concentrent sur un élément d'entrée au chargement de la page, sur iOS. Je suppose que Apple a décidé de faire quelque chose pour empêcher cela. Je ne suis donc pas d'accord avec @DA: il s'agit d'une fonctionnalité et non d'un bug.

Il n'y a pas de solution de contournement connue pour cela, vous devrez donc abandonner l'idée d'utiliser un délai.

Mise à jour août 2012:

À partir de iOS 5, les gestionnaires déclenchés par des événements de clic synthétisés sont autorisés à déclencher le focus sur les éléments d'entrée. Essayez l'exemple de focus d'entrée FastClick mis à jour .

80

J'ai pu élever le clavier en envoyant un événement click uniquement lorsque l'événement d'origine provenait d'une interaction utilisateur, et non de setTimeout. Je crois que le résultat est que vous pouvez relever le clavier d'un événement touchend, mais pas d'un délai d'attente.

5
Nick Saretzky

Il semble que focus () ne fonctionne que si vous avez ajouté le site à l'écran d'accueil et ouvert le site avec ce lien.

1
elweilando

J'étais capable de faire fonctionner .focus () en l'attachant à deux événements distincts dans la carte des événements, mais c'est un peu hacky.

Après avoir ajouté FastClick.js, voici ce qui se passe dans iOS: .focus () ne fonctionne que s’il est activé par une fonction attachée à un événement. MAIS le focus est également un événement dans la carte des événements de safari mobile qui est réellement appelé lorsque vous utilisez .focus () de jQuery. SO vous pouvez être redondant et attacher un autre .focus () à l'événement de focus de l'objet pour vous assurer qu'il passe au travers. Cela fonctionne particulièrement bien lorsque vous créez une entrée dans le DOM. J'aime récemment programmer pour MeteorJS, voici à quoi ressemble la solution:

Template.templateName.events({
    "click button":function(){
        Session.set("makeButtonVisible",true);
        $("input.created").focus();
    },
    "focus input.created":function(){
        $("input.created").focus();
    }
});

J'espère que cela est utile à quelqu'un qui m'a pris environ deux heures pour comprendre celui-ci.

EDIT: .__ Eh bien, pour MeteorJS en particulier, vous ne pouvez pas non plus utiliser la fonction Template.templateName.rendered car le .focus () doit être appelé à partir d'un événement. MAIS pour une raison quelconque, lorsque vous ajoutez une entrée via jQuery, vous pouvez vous concentrer dessus dans l’événement. Je suppose que c'est la voie à suivre. C'est ce que j'ai fini par faire:

Template.templateName.events({
    "click button":function(){
        $("body").append("<input class='created' type='tel'>");
        $("input.created").focus();
    }
});
0
Marz

Ajout à la réponse de Matt. Au moins sur Safari sur iOS 5.1, ce problème est résolu. Votre FastClick fonctionne, c’est-à-dire que la synthèse d’un événement de clic n’échouera pas le focus. Toutefois, cela n’aide pas les personnes qui souhaitent que leur code focus() fonctionne sur toutes les versions d’IOS, soupir.

0
dodysw