Mobile Safari: Javascript focus () -Methode im Eingabefeld funktioniert nur mit Klick?


75

Ich habe ein einfaches Eingabefeld wie dieses.

<div class="search">
   <input type="text" value="y u no work"/>
</div>​

Und ich versuche focus()es innerhalb einer Funktion. Innerhalb einer Zufallsfunktion (egal welche Funktion es ist) habe ich diese Zeile…

$('.search').find('input').focus();

Dies funktioniert auf jedem Desktop einwandfrei.

Auf meinem iPhone funktioniert es jedoch nicht. Das Feld wird nicht fokussiert und die Tastatur wird auf meinem iPhone nicht angezeigt.

Zu Testzwecken und um euch das Problem zu zeigen, habe ich eine kurze Probe gemacht:

$('#some-test-element').click(function() {
  $('.search').find('input').focus(); // works well on my iPhone - Keyboard slides in
});

setTimeout(function() {
  //alert('test'); //works
  $('.search').find('input').focus(); // doesn't work on my iPhone - works on Desktop
}, 5000);​

Irgendeine Idee, warum das focus()mit der Timeout-Funktion auf meinem iPhone nicht funktionieren würde.

Testen Sie diese Geige auf Ihrem iPhone, um das Live-Beispiel zu sehen. http://jsfiddle.net/Hc4sT/

Aktualisieren:

Ich habe genau den gleichen Fall erstellt, mit dem ich derzeit in meinem aktuellen Projekt konfrontiert bin.

Ich habe ein Auswahlfeld, das - wenn "geändert" - den Fokus auf das Eingabefeld setzen und das Kexboard auf dem iPhone oder anderen Mobilgeräten einschieben soll. Ich habe herausgefunden, dass der Fokus () richtig eingestellt ist, aber die Tastatur nicht angezeigt wird. Ich brauche die Tastatur, um zu erscheinen.


vielleicht ist es ist konzentriert, aber die Tastatur nur nicht angezeigt (das ist der Fall auf meinem Nokia X6).
11684

1
funktioniert bei mir. jsfiddle du hast gerade die box fokussiert und öffne eine tastatur auf meinem iphone. Welches iOS benutzt du? Ich habe mit 5.1 überprüft.
Krizz

Ok, du hast recht, wie es scheint. Ich bin auf iOS 5.1.1. Der Fokus () scheint zu funktionieren, wie ich weiß, input:focus { background:green; }über CSS auf den Eingang gesetzt. Die Tastatur passt jedoch nicht zu mir. Sehen Sie sich diesen Arbeitsfall an, an dem ich gerade arbeite. cl.ly/1d210x1W3Y3W Testen Sie dies auf Ihrem iPhone. Gibt es eine Möglichkeit, die Tastatur zu verschieben, wenn Sie im Auswahlfeld "Suchen" auswählen?
Matt

1
Ich versuche eine Menge Dinge. Ich habe triggerHandler (), focusin (), trigger ("focus") ausprobiert. Ich habe sogar versucht, es zuerst zu verwischen und dann den Fokus wieder hinzuzufügen. Ich denke, es könnte ein Fehler im Webkit sein. Sie könnten mit diesem einen Pech haben ... Aber ich werde noch ein paar Dinge versuchen ...
Alex

1
Ich gebe auf. Ich habe alles versucht. Dies können Sie im iOS Safari-Webbrowser einfach nicht tun. Hoffentlich nimmt Apple eine Änderung vor, um dies zu ermöglichen, da ich dies sicherlich nicht als "Feature" betrachte! haha Ich weiß nicht, warum man das Feld so leicht verwischen kann (), aber nicht fokussieren kann. Macht für mich keinen Sinn.
Alex

Antworten:


77

Eigentlich, Leute, gibt es einen Weg. Ich hatte große Mühe, dies für [LINK REMOVED] herauszufinden (probieren Sie es auf einem iPhone oder iPad aus).

Grundsätzlich ist Safari auf Touchscreen-Geräten geizig, wenn es um focus()Textfelder geht. Sogar einige Desktop-Browser sind besser, wenn Sie dies tun click().focus(). Die Entwickler von Safari auf Touchscreen-Geräten stellten jedoch fest, dass es für Benutzer ärgerlich ist, wenn die Tastatur immer wieder hochgefahren wird. Daher wurde der Fokus nur auf die folgenden Bedingungen gerichtet:

1) Der Benutzer hat irgendwo geklickt und focus()wurde beim Ausführen des Klickereignisses aufgerufen. Wenn Sie einen AJAX-Aufruf ausführen, müssen Sie dies synchron ausführen, z. B. mit der veralteten (aber immer noch verfügbaren) $.ajax({async:false})Option in jQuery.

2) Außerdem - und dieser hat mich eine Weile beschäftigt - focus()scheint es immer noch nicht zu funktionieren, wenn ein anderes Textfeld gerade fokussiert ist. Ich hatte eine "Go" -Schaltfläche, die AJAX ausführte, also habe ich versucht, das Textfeld beim touchstartEreignis der Go-Schaltfläche zu verwischen , aber dadurch wurde die Tastatur einfach ausgeblendet und das Ansichtsfenster verschoben, bevor ich die Möglichkeit hatte, den Klick auf die Go-Schaltfläche abzuschließen . Schließlich habe ich versucht, das Textfeld beim Klicken auf die touchendSchaltfläche " Verwischen" zu verwischen , und das hat wie ein Zauber funktioniert!

Wenn Sie # 1 und # 2 zusammenfügen, erhalten Sie ein magisches Ergebnis, das Ihre Anmeldeformulare von allen beschissenen Web-Anmeldeformularen unterscheidet, indem Sie den Fokus in Ihre Passwortfelder legen und sie sich nativer anfühlen lassen. Genießen! :) :)


2
Das klingt sehr intelligent, aber es fällt mir schwer, "# 1 und # 2 zusammenzufügen". Wenn ein Benutzer in meiner App mit jQueryMobile auf ein Listenelement auf Seite A klickt, wird eine neue Seite B geöffnet, die nur eine sichtbare Eingabe enthält. Ich möchte, dass die Tastatur für diese Eingabe automatisch geöffnet wird. Wollen Sie damit sagen, dass ich den Aufruf von .focus () irgendwo im Klick-Handler auf Seite A platzieren muss?
Wytze

1
Danke, dass du mir Zeit gespart hast. Das war so offensichtlich.
Vogdb

4
Ich konnte es bekommen! Statt zu verwischen und das Element konzentriert, habe ich einfach hinzugefügt event.preventDefault()auf touchstart. Beachten Sie, dass dies die Ausführung des ng-Klicks verhindert, sodass ich meine Klartextlogik in den Ereignishandler $scope.$apply()
einfügen musste

2
Ich fand, dass es input.focus()funktionierte , nur vom Klick-Handler einer Schaltfläche aus zu laufen . Safari auf iPhone 5 und iPad. Wenn ich das focus()in einem setTimeout hatte, hat das nicht funktioniert. Vielleicht bedeutet das "synchron", @Michael.
Dan Dascalescu

1
Vielen Dank, dass Sie eine aktuelle Lösung veröffentlicht haben. Das Verwischen des vorherigen Elements am Touchend + das Setzen des Fokus auf das Klickereignis funktioniert in iOS10 weiterhin.
Kirill E.

18

Eine native Javascript-Implementierung der Antwort von WunderBart.

function onClick() {

  // create invisible dummy input to receive the focus first
  const fakeInput = document.createElement('input')
  fakeInput.setAttribute('type', 'text')
  fakeInput.style.position = 'absolute'
  fakeInput.style.opacity = 0
  fakeInput.style.height = 0
  fakeInput.style.fontSize = '16px' // disable auto zoom

  // you may need to append to another element depending on the browser's auto 
  // zoom/scroll behavior
  document.body.prepend(fakeInput)

  // focus so that subsequent async focus will work
  fakeInput.focus()

  setTimeout(() => {

    // now we can focus on the target input
    targetInput.focus()

    // cleanup
    fakeInput.remove()
    
  }, 1000)

}

Weitere Referenzen: Deaktivieren Sie die automatische Vergrößerung des Eingabe-Tags "Text" - Safari auf dem iPhone


1
Das hat bei mir funktioniert. Wenn Sie verhindern möchten, dass die Tastatur im fakeInput-Fokus angezeigt wird, fügen Sie readonly = "true" hinzu.
Branislav Kuliha

Einzige Lösung, die funktioniert. requestAnimationFrame ist für mich ausreichend und beseitigt die Verzögerung.
Thomas

Diese Antwort sollte für andere ähnliche Probleme verwendet werden, bei denen setTimeout + sich auf Safari-Browser konzentriert. Es ist das Einzige, was wirklich funktioniert!
ging

Vielen Dank! Dies ist die einzige Lösung, die für mich funktioniert hat.
Offek

5

Ich hatte kürzlich das gleiche Problem. Ich habe eine Lösung gefunden, die anscheinend für alle Geräte funktioniert. Sie können den asynchronen Fokus nicht programmgesteuert ausführen, aber Sie können den Fokus auf Ihre Zieleingabe umschalten , wenn eine andere Eingabe bereits fokussiert ist. Sie müssen also eine gefälschte Eingabe erstellen, ausblenden, an DOM anhängen und eine gefälschte Eingabe auf das Triggerereignis fokussieren. Wenn die asynchrone Aktion abgeschlossen ist, rufen Sie einfach erneut den Fokus auf die Zieleingabe auf. Hier ist ein Beispiel-Snippet - führen Sie es auf Ihrem Handy aus.

bearbeiten:

Hier ist eine Geige mit dem gleichen Code . Anscheinend können Sie keine angehängten Snippets auf Mobiltelefonen ausführen (oder ich mache etwas falsch).

var $triggerCheckbox = $("#trigger-checkbox");
var $targetInput = $("#target-input");

// Create fake & invisible input
var $fakeInput = $("<input type='text' />")
  .css({
    position: "absolute",
    width: $targetInput.outerWidth(), // zoom properly (iOS)
    height: 0, // hide cursor (font-size: 0 will zoom to quarks level) (iOS)
    opacity: 0, // make input transparent :]
  });

var delay = 2000; // That's crazy long, but good as an example

$triggerCheckbox.on("change", function(event) {
  // Disable input when unchecking trigger checkbox (presentational purpose)
  if (!event.target.checked) {
    return $targetInput
      .attr("disabled", true)
      .attr("placeholder", "I'm disabled");
  }

  // Prepend to target input container and focus fake input
  $fakeInput.prependTo("#container").focus();

  // Update placeholder (presentational purpose)
  $targetInput.attr("placeholder", "Wait for it...");

  // setTimeout, fetch or any async action will work
  setTimeout(function() {

    // Shift focus to target input
    $targetInput
      .attr("disabled", false)
      .attr("placeholder", "I'm alive!")
      .focus();

    // Remove fake input - no need to keep it in DOM
    $fakeInput.remove();
  }, delay);
});
label {
  display: block;
  margin-top: 20px;
}

input {
  box-sizing: border-box;
  font-size: inherit;
}

#container {
  position: relative;
}

#target-input {
  width: 250px;
  padding: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="container">
  <input type="text" id="target-input" placeholder="I'm disabled" />

  <label>
    <input type="checkbox" id="trigger-checkbox" />
    focus with setTimetout
   </label>
</div>


Dies ist die beste Lösung, die ich bisher gefunden habe.
anwerso

Sie können den fontSize: '16px'automatischen Zoom deaktivieren. Siehe auch meine Antwort unten für die native js-Implementierung.
Raine Revere

3

Ich habe ein Suchformular mit einem Symbol, das den Text beim Klicken löscht. Das Problem (auf Mobilgeräten und Tablets) bestand jedoch darin, dass die Tastatur ausgeblendet / ausgeblendet wurde, da das clickentfernte Ereignis aus dem entfernt focuswurde input.

Textsucheingabe mit Schließsymbol

Ziel : Nach dem Löschen des Suchformulars (Klicken / Tippen auf das X-Symbol) die Tastatur sichtbar halten !

Um dies zu erreichen, bewerben Sie sich stopPropagation()für die Veranstaltung wie folgt:

function clear ($event) {
    $event.preventDefault();
    $event.stopPropagation();
    self.query = '';
    $timeout(function () {
        document.getElementById('sidebar-search').focus();
    }, 1);
}

Und das HTML-Formular:

<form ng-controller="SearchController as search"
    ng-submit="search.submit($event)">
        <input type="search" id="sidebar-search" 
            ng-model="search.query">
                <span class="glyphicon glyphicon-remove-circle"
                    ng-click="search.clear($event)">
                </span>
</form>

3

Diese Lösung funktioniert gut, ich habe auf meinem Handy getestet:

document.body.ontouchend = function() { document.querySelector('[name="name"]').focus(); };

genießen


Das funktioniert fast. Aber skaliert nicht auf zwei Datumsfelder und macht die Seite ein bisschen unangenehm
Shayne

Vielen Dank! Versuchte alle möglichen Sachen und dies tat es schließlich für mich, wo aus irgendeinem Grund document.getElementById nicht
daamsie

2

Ich habe es geschafft, dass es mit dem folgenden Code funktioniert:

event.preventDefault();
timeout(function () {
    $inputToFocus.focus();
}, 500);

Ich benutze AngularJS, also habe ich eine Direktive erstellt, die mein Problem gelöst hat:

Richtlinie:

angular.module('directivesModule').directive('focusOnClear', [
    '$timeout',
    function (timeout) {
        return {
            restrict: 'A',
            link: function (scope, element, attrs) {
                var id = attrs.focusOnClear;
                var $inputSearchElement = $(element).parent().find('#' + id);
                element.on('click', function (event) {
                    event.preventDefault();
                    timeout(function () {
                        $inputSearchElement.focus();
                    }, 500);
                });
            }
        };
    }
]);

Verwendung der Richtlinie:

<div>
    <input type="search" id="search">
    <i class="icon-clear" ng-click="clearSearchTerm()" focus-on-clear="search"></i>
</div>

Es sieht so aus, als würden Sie jQuery verwenden, daher weiß ich nicht, ob die Anweisung hilfreich ist.


2
Es ist bekannt, dass dies auf ios safari nicht funktioniert. Safari unterscheidet speziell zwischen Ereignissen, die durch Benutzerinteraktion generiert wurden, und Ereignissen, die ausschließlich aus dem js selbst generiert wurden, und liefert auf diese Weise keine Fokus- / Auswahlereignisse.
Ben Wheeler

Nun, das ist nicht wahr und ich verwende es in meinen Apps mit Cordova / Phonegap ... Und warum abstimmen? Wie unterscheidet sich meine Antwort von den anderen? Außer ich habe eine Winkelrichtlinie erstellt, die Sie verwenden können.
Martinmose

Normalerweise reicht bei Angular eine Zeitüberschreitung aus. Sie müssen den Zeitüberschreitungswert nicht festlegen. Es lässt es auf den Digest-Zyklus warten und läuft somit zu einem Zeitpunkt, an dem die anderen Ereignisse, die den Fokus behindern, abgeschlossen sind.
Maarten

Hallo @ Maarten, danke für deinen Kommentar, meinst du die 500, die ich für das Timeout eingestellt habe? :)
Martinmose

Okay, ich werde das testen. Vielen Dank :).
Martinmose

1

AKTUALISIEREN

Ich habe es auch versucht, aber ohne Erfolg:

$(document).ready(function() {
$('body :not(.wr-dropdown)').bind("click", function(e) {
    $('.test').focus();
})
$('.wr-dropdown').on('change', function(e) {
    if ($(".wr-dropdow option[value='/search']")) {
        setTimeout(function(e) {
            $('body :not(.wr-dropdown)').trigger("click");
        },3000)         
    } 
}); 

});

Ich bin verwirrt darüber, warum Sie sagen, dass dies nicht funktioniert, weil Ihre JSFiddle einwandfrei funktioniert, aber hier ist trotzdem mein Vorschlag ...

Probieren Sie diese Codezeile in Ihrer SetTimeOut-Funktion für Ihr Klickereignis aus:

document.myInput.focus();

myInput korreliert mit dem Namensattribut des Eingabe-Tags.

<input name="myInput">

Und verwenden Sie diesen Code, um das Feld zu verwischen:

document.activeElement.blur();

Vielen Dank, siehe mein Update in meiner Frage. Ich kann es auch nicht mit Ihrem Vorschlag zum Laufen bringen.
Matt


-3

Bitte versuchen Sie, das Ereignis on-tap anstelle von ng-click zu verwenden. Ich hatte dieses Problem. Ich habe es behoben, indem ich meine Schaltfläche zum Löschen des Suchfelds in der Beschriftung des Suchformulars erstellt und den Klick auf die Schaltfläche zum Löschen durch Tippen ersetzt habe. Es funktioniert jetzt gut.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.