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

Posted

技术标签:

【中文标题】移动 Safari:输入字段上的 Javascript focus() 方法仅适用于点击?【英文标题】:Mobile Safari: Javascript focus() method on inputfield only works with click? 【发布时间】:2012-08-25 15:15:20 【问题描述】:

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

<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() 设置正确,但键盘没有出现。我需要键盘出现。

【问题讨论】:

也许它专注的,但是键盘没有出现(我的诺基亚 X6 就是这种情况)。 为我工作。您粘贴的 jsfiddle 只是将框聚焦并在我的 iphone 上打开一个键盘。你用的是哪个ios?我已经检查了 5.1。 好吧,看起来你是对的。我在 iOS 5.1.1 上。正如我所知,focus() 似乎可以通过 css 在输入上设置input:focus background:green; 。但是键盘不适合我。请参阅我目前正在处理的这个工作案例。 cl.ly/1d210x1W3Y3W 在你的 iPhone 上测试。在选择框中选择“搜索”时是否有机会在键盘中滑动? 我正在尝试很多东西。我尝试了 triggerHandler()、focusin()、trigger("focus")。我什至试图先模糊它,然后重新添加焦点。我认为这可能是 webkit 中的一个错误。你可能对这个不走运......但我会尝试更多的东西...... 我放弃了。我什么都试过了。这不是您可以在 iOS Safari Web 浏览器中执行的操作。希望 Apple 做出改变以允许这样做,因为我当然不认为这是一个“功能”!哈哈,我不知道为什么您可以如此轻松地模糊()该字段但无法为其设置焦点。对我来说没有意义。 【参考方案1】:

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)


其他参考:Disable Auto Zoom in Input "Text" tag - Safari on iPhone

【讨论】:

这对我有用。如果您想防止在 fakeInput 焦点上显示键盘,请将 readonly="true" 添加到它。 唯一有效的解决方案。 requestAnimationFrame 对我来说就足够了,并且消除了延迟。 这个答案应该与其他类似的问题共享,这些问题涉及使 setTimeout + 专注于 Safari 浏览器。这是真正有效的一件事! 谢谢!这是唯一对我有用的解决方案。 作品,+1。但似乎超时很重要,0 或像 250 毫秒这样的小时间间隔它不起作用。苹果人应该为自己感到羞耻,因为他们把微不足道的任务变成了巨大而不透明的东西。【参考方案2】:

试试这个:

input.focus();
input.scrollIntoView()

【讨论】:

【参考方案3】:

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

基本上,触摸屏设备上的 Safari 对focus()ing 文本框很吝啬。如果您使用click().focus(),即使某些桌面浏览器也会做得更好。但是触摸屏设备上 Safari 的设计者意识到,当键盘不断出现时会让用户感到厌烦,因此他们只在以下情况下才会出现焦点:

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

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

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

【讨论】:

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

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

编辑:

这是fiddle with the same code。显然你不能在手机上运行附加的 sn-ps(或者我做错了什么)。

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>

【讨论】:

这是迄今为止我找到的最好的解决方案。 您可以设置fontSize: '16px'禁用自动缩放。另外,请参阅下面有关本机 js 实现的答案。 仅供参考,截至 iOS14 仍在工作。我把头敲在键盘上试图找出解决方案,这就像一个魅力。我确实发现假输入适用于相对定位和显示:无。 从头开始 - display:none 仅适用于 android【参考方案5】:

请尝试使用 on-tap 而不是 ng-click 事件。我有这个问题。我通过在搜索表单标签中创建清除搜索框按钮并通过点击替换清除按钮的 ng-click 来解决它。现在可以正常使用了。

【讨论】:

【参考方案6】:

这个方案效果很好,我在手机上测试过:

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

享受

【讨论】:

这几乎可以工作。但不能扩展到两个日期字段,并且有点使页面有点小故障 谢谢!尝试了各种各样的东西,这终于为我做到了,由于某种原因 document.getElementById 没有【参考方案7】:

我有一个带有图标的搜索表单,单击该图标会清除文本。但是,问题(在手机和平​​板电脑上)是键盘会折叠/隐藏,因为 click 事件已从 focus 中删除,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>

【讨论】:

【参考方案8】:

我设法使它与以下代码一起工作:

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

【讨论】:

已知这不适用于 ios safari。 Safari 特别区分了用户交互产生的事件和纯粹由 js 本身产生的事件,并且不会以这种方式传递焦点/选择事件。 嗯,这不是真的,我在我的应用程序上使用它与 Cordova/Phonegap... 为什么要投反对票?我的答案与其他人有何不同?除了我创建了一个你可以使用的 Angular 指令。 通常在 Angular 上,超时本身就足够了,您不需要设置超时值。它使它等待摘要周期,因此在其他阻碍焦点的事件完成时运行。 嗨@Maarten 感谢您的评论,您的意思是我设置的500 超时? :) 好的,我会测试一下。谢谢:)。【参考方案9】:

更新

我也试过了,但没用:

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

【讨论】:

谢谢,在我的问题中查看我的更新。我似乎也无法满足您的建议。

以上是关于移动 Safari:输入字段上的 Javascript focus() 方法仅适用于点击?的主要内容,如果未能解决你的问题,请参考以下文章

iOS 移动浏览器和 OS X Safari 上的 Flexbox 奇怪行为

iOS Safari(移动)和 Angular Material UI:专注于输入字段时不需要的闪烁文本

专注于输入字段和方向更改会扰乱 iOS 6 Safari 上的缩放级别

用户选择:无导致 Safari 上无法访问输入字段

在 iOS 上的 Safari 中全屏打开网页

单击 Chrome 和 Safari 中的输入字段后的奇怪行为