web-dev-qa-db-ja.com

Mobile Safari:入力フィールドのJavascript focus()メソッドはクリックでのみ機能しますか?

この問題の解決策が見つからないようです。

このような単純な入力フィールドがあります。

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

そして、関数内でfocus()それをしようとしています。ランダム関数の内部(それがどの関数であるかは関係ありません)私はこの行を持っています…

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

これは、すべてのデスクトップで問題なく機能します。

ただし、私のiPhoneでは機能しません。フィールドがフォーカスされておらず、キーボードがキーボードに表示されません。

テストの目的と、皆さんに問題を示すために、簡単なサンプルを作成しました。

$('#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);​

focus()がiPhoneのタイムアウト機能で動作しない理由は何でも考えてください。

ライブの例を見るには、iPhoneでこのフィドルをテストしてください。 http://jsfiddle.net/Hc4sT/

更新:

現在のプロジェクトで現在直面しているのとまったく同じケースを作成しました。

「変更」されたときに-入力フィールドにフォーカスを設定し、iPhoneまたは他のモバイルデバイスのkexboardをスライドインする選択ボックスがあります。 focus()は正しく設定されていますが、キーボードが表示されないことがわかりました。キーボードを表示する必要があります。

ここにテストファイルをアップロードしました http://cl.ly/1d210x1W3Y3W …iPhoneでこれをテストすると、キーボードがスライドインしないことがわかります。

63
matt

実際、みんな、方法があります。 http://forstartersapp.com (iPhoneまたはiPadで試してみてください)についてこれを理解するのに苦労しました。

基本的に、タッチスクリーンデバイスのSafariは、focus()ingテキストボックスに関してはケチです。 click().focus()を実行すると、一部のデスクトップブラウザーのパフォーマンスが向上します。しかし、タッチスクリーンデバイスのSafariの設計者は、キーボードが表示され続けるとユーザーに迷惑をかけることに気づいたため、次の条件にのみ焦点を合わせました。

1)ユーザーがどこかをクリックし、クリックイベントの実行中にfocus()が呼び出されました。 AJAX呼び出しを実行している場合、must廃止された(ただしまだ利用可能)$.ajax({async:false}) jQueryのオプション。

2)さらに-そして、これはしばらくの間私を忙しくさせた-focus()は、他のテキストボックスがその時点でフォーカスされている場合、まだ動作していないようです。 AJAXを実行する「Go」ボタンがあったので、Goボタンのtouchstartイベントでテキストボックスをぼかすことを試みましたが、キーボードを非表示にし、ビューポートを移動してから、 [Go]ボタンをクリックします。最後に、[Go]ボタンのtouchendイベントでテキストボックスをぼかしてみましたが、これは魅力のように機能しました。

#1と#2を組み合わせると、パスワードフィールドにフォーカスを置くことで、ログインフォームをすべての安っぽいWebログインフォームと区別する魔法のような結果が得られ、よりネイティブな感じになります。楽しい! :)

69

WunderBartの答えのネイティブjavascript実装。

自動ズームを無効にします フォントサイズを使用

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)

}
6
Raine Revere

私は最近同じ問題に直面しました。明らかに、すべてのデバイスで機能するソリューションを見つけました。プログラムで非同期フォーカスを行うことはできませんが、他の入力が既にフォーカスされている場合、ターゲット入力にswitchフォーカスすることはできます。だからあなたがする必要があるのは、DOMに作成、非表示、追加し、トリガーイベントでfake入力をフォーカスし、非同期アクションが完了したら、呼び出すだけですターゲット入力に再び焦点を合わせます。これがスニペットの例です。モバイルで実行してください。

編集:

同じコードのフィドル です。どうやら、添付されたスニペットをモバイルで実行できないようです(または、私は何か間違ったことをしています)。

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>
5
WunderBart

私はそれを次のコードで動作させることができました:

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

私はAngularJSを使用しているので、問題を解決するディレクティブを作成しました:

ディレクティブ:

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);
                });
            }
        };
    }
]);

ディレクティブの使用方法:

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

JQueryを使用しているように見えるので、このディレクティブが助けになるかどうかはわかりません。

2
martinmose

クリックするとテキストがクリアされるアイコンのある検索フォームがあります。ただし、(モバイルとタブレットの)問題は、clickイベントが削除されたfocusinputから削除されたため、キーボードが折りたたまれたり非表示になったりすることでした。

text search input with close icon

目標:検索フォームをクリアした後(xアイコンをクリック/タップ)キーボードを表示したまま

これを実現するには、次のようにイベントにstopPropagation()を適用します。

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

そして、HTMLフォーム:

<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>
2
DeBraid

UPDATE

私もこれを試しましたが、役に立ちませんでした:

$(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)         
    } 
}); 

});

あなたのJSFiddleがうまく機能しているのでこれが機能していないとあなたが言う理由について私は混乱していますが、とにかく私の提案は...

クリックイベントのSetTimeOut関数で次のコード行を試してください。

document.myInput.focus();

myInputは、入力タグの名前属性と相関しています。

<input name="myInput">

そして、このコードを使用してフィールドをぼかします:

document.activeElement.blur();
1
Alex

このソリューションはうまく機能します。電話でテストしました。

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

楽しい

1
istvan makary