移动 Safari:输入字段上的 Javascript focus() 方法仅适用于单击?

IT技术 javascript jquery iphone input focus
2021-02-02 13:36:53

我有一个像这样的简单输入字段。

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

我正在尝试focus()在一个函数中使用它。所以在一个随机函数里面(不管它是什么函数)我有这条线......

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

这在任何桌面上都可以正常工作。

但是它在我的 iPhone 上不起作用。该字段未聚焦,并且我的 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() 设置正确,但键盘没有显示。我需要键盘出现。

6个回答

事实上,伙计们,有办法。我费了很大劲才为 [LINK REMOVED] 弄清楚了这一点(在 iPhone 或 iPad 上试试)。

基本上,触摸屏设备上的 Safari 在focus()处理文本框时很吝啬如果您这样做,甚至某些桌面浏览器也会做得更好click().focus()但触屏设备上的 Safari 设计者意识到,当键盘不断出现时对用户来说很烦人,因此他们只关注以下情况:

1) 用户点击某处并focus()在执行点击事件时被调用。如果您正在执行 AJAX 调用,那么您必须同步执行,例如使用$.ajax({async:false})jQuery 中已弃用(但仍然可用)的选项。

2) 此外——这个让我忙了一段时间——focus()如果当时关注其他一些文本框,似乎仍然不起作用。我有一个执行 AJAX 的“Go”按钮,所以我尝试touchstart在 Go 按钮事件上模糊文本框,但这只会让键盘消失并在我有机会完成点击 Go 按钮之前移动了视口. 最后,我尝试touchend在 Go 按钮事件上模糊文本框,这就像一个魅力!

当您将#1 和#2 放在一起时,您会得到一个神奇的结果,它将您的登录表单与所有蹩脚的 Web 登录表单区分开来,通过将焦点放在您的密码字段中,并使它们感觉更原生。享受!:)

这听起来很聪明,但我很难“将#1 和#2 放在一起”。在我的应用程序中,使用 jQueryMobile,当用户单击页面 A 中的列表项时,会打开一个只有一个可见输入的新页面 B。我希望键盘为该输入自动打开。您的意思是说我必须将 .focus() 调用放在页面 A 的单击处理程序中的某个位置吗?
2021-03-21 13:36:53
谢谢你节省了我的时间。那太难找了。
2021-03-30 13:36:53
感谢您发布实际解决方案。在 touchend 上模糊上一个元素 + 将焦点设置在点击事件上在 iOS10 中仍然有效。
2021-03-31 13:36:53
我能够得到它!我没有模糊和聚焦元素,而是简单地添加event.preventDefault()touchstart. 请注意,这会阻止 ng-click 执行,因此我必须在事件处理程序中添加我的明文逻辑,并且$scope.$apply()
2021-04-06 13:36:53
我发现只是input.focus()从按钮的点击处理程序运行,工作。iPhone 5 和 iPad 上的 Safari。如果我focus()在 setTimeout 中有 ,那将不起作用。所以也许这就是“同步”的意思,@Michael。
2021-04-08 13:36:53

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)

}

其他参考:在输入“文本”标签中禁用自动缩放 - iPhone 上的 Safari

作品,+1。但似乎超时很重要,0 或像 250 毫秒这样的小时间流逝是行不通的。苹果人应该为自己感到羞耻,因为他们把琐碎的任务变成了巨大而不透明的东西。
2021-03-16 13:36:53
唯一有效的解决方案。requestAnimationFrame 对我来说已经足够了,并且消除了延迟。
2021-03-28 13:36:53
这对我有用。如果您想防止在 fakeInput 焦点上显示键盘,请添加 readonly="true" 到它。
2021-04-01 13:36:53
谢谢!这是唯一对我有用的解决方案。
2021-04-09 13:36:53
这个答案应该在处理 setTimeout + 关注 Safari 浏览器的其他类似问题中共享。这是真正有效的一件事!
2021-04-12 13:36:53

我最近遇到了同样的问题。我找到了一个显然适用于所有设备的解决方案。您不能以编程方式进行异步焦点,但是当其他一些输入已经聚焦时,您可以焦点切换到目标输入。因此,您需要做的是创建、隐藏、附加到 DOM 并将输入聚焦在触发器事件上,当异步操作完成时,只需再次在目标输入上调用焦点即可。这是一个示例片段 - 在您的手机上运行它。

编辑:

这是一个具有相同代码小提琴显然你不能在手机上运行附加的片段(或者我做错了什么)。

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>

这是我目前找到的最好的解决方案。
2021-03-18 13:36:53
您可以设置fontSize: '16px'禁用自动缩放。另外,请参阅下面有关本机 js 实现的答案。
2021-03-19 13:36:53
仅供参考,从 iOS14 开始仍然有效。用我的头敲击键盘试图找出解决方案,这就像一个魅力。我确实发现假输入在相对定位和 display:none 下工作正常。
2021-03-28 13:36:53
从头开始 - display:none 仅适用于 Android。
2021-04-05 13:36:53

我设法使用以下代码使其工作:

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,所以我不知道该指令是否有任何帮助。

好的,我会测试一下。谢谢 :)。
2021-03-29 13:36:53
嗯,这不是真的,我在我的应用程序中使用它与 Cordova/Phonegap ......为什么不投票?我的回答和别人的有什么不同?除了我创建了一个可以使用的 Angular 指令。
2021-04-01 13:36:53
通常在 Angular 上,超时本身就足够了,您不需要设置超时值。它使其等待摘要循环,从而在其他阻碍焦点的事件完成时运行。
2021-04-06 13:36:53
嗨@Maarten 感谢您的评论,您的意思是我在超时时设置的 500?:)
2021-04-07 13:36:53
众所周知,这不适用于 ios safari。Safari 特别区分了由用户交互生成的事件与完全由 js 本身生成的事件,并且不会以这种方式传递焦点/选择事件。
2021-04-12 13:36:53

我有一个带有图标的搜索表单,单击时会清除文本。然而,这个问题(在移动和平板电脑)是,键盘会崩溃/隐藏,因为click删除事件focus从取出input

带有关闭图标的文本搜索输入

目标:清除搜索表单(单击/点击 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>