为 Chrome 选择焦点错误寻找更好的解决方法

Posted

技术标签:

【中文标题】为 Chrome 选择焦点错误寻找更好的解决方法【英文标题】:Looking for a better workaround to Chrome select on focus bug 【发布时间】:2011-03-23 18:25:44 【问题描述】:

我和this question中的用户有同样的问题,这是由于Webkit中的this bug造成的。但是,提供的解决方法不适用于我的应用程序。让我重新陈述这个问题,这样你就不必去阅读另一个问题了:

当它获得焦点时,我试图选择文本区域中的所有文本。以下 jQuery 代码适用于 IE/FF/Opera:

$('#out').focus(function()
  $('#out').select();
);

但是,在 Chrome/Safari 中,文本被选中——非常短暂——但随后触发 mouseUp 事件并取消选择文本。上述链接中提供了以下解决方法:

$('#out').mouseup(function(e)
  e.preventDefault();
);

但是,这种解决方法对我没有好处。当用户给 textarea 焦点时,我想选择所有文本 only。如果他选择,他必须然后能够只选择部分文本。谁能想到仍然满足此要求的解决方法?

【问题讨论】:

一个大 +1 用于发现最常见的问题解决方案中明显的明显缺陷。 【参考方案1】:

这个怎么样?

$('#out').focus(function () 
    $('#out').select().mouseup(function (e) 
        e.preventDefault();
        $(this).unbind("mouseup");
    );
);

【讨论】:

可能.one() 是一个更好的方法。 +1。我不明白为什么这么多人认为基本的preventDefault() 修复就足够了。它显然有严重的缺陷,但它被建议作为你所看到的任何地方的解决方案。谢谢你解决它。 (虽然是的,我同意@InviS 的观点,.one() 可能是更好的做法) .one() 会更好,但这不能很好地处理选项卡式焦点。 这里是如何使用 jQuery 的 .one() 来做到这一点,正如 @InviS 所建议的那样:$('#out').focus(function () $('#out').select().one('mouseup', function (e) e.preventDefault(); ); );【参考方案2】:

接受的答案(以及到目前为止我发现的所有其他解决方案)不适用于键盘焦点,即。 e.按标签,至少在我的 Chromium 21 中没有。我使用以下 sn-p 代替:

$('#out').focus(function () 
  $(this).select().one('mouseup', function (e) 
    $(this).off('keyup');
    e.preventDefault();
  ).one('keyup', function () 
    $(this).select().off('mouseup');
  );
);

keyupfocus 处理程序中的e.preventDefault() 无济于事,因此键盘焦点后的取消选择似乎不会发生在它们的默认处理程序中,而是发生在 focuskeyup 事件之间。

正如@BarelyFitz 所建议的,使用命名空间事件可能会更好,以免意外解除绑定其他事件处理程序。将'keyup' 替换为'keyup.selectText',将'mouseup' 替换为'mouseup.selectText'

【讨论】:

当您取消绑定事件时,您可能会无意中取消绑定可能在输入上的其他处理程序。为了防止这种情况,您可以使用命名空间,例如“mouseup.selectText”而不是“mouseup”,那么只会删除您的单个事件处理程序。 结合命名空间提示,这是我为这个粘性检票口找到的最佳解决方案,我将它推荐给房子。【参考方案3】:

为什么不简单:

$('#out').focus(function()
    $(this).one('mouseup', function() 
        $(this).select();
    );
);

似乎适用于所有主要浏览器...

【讨论】:

这对我有用。值得注意的是,当您专注于通过代码进行输入时,它似乎不起作用。为了解决这个问题,我使用$('#element').select().focus() 而不是$('#element').focus()【参考方案4】:

一个非常不同的方法是将焦点事件与鼠标序列分开。这对我来说非常有效——没有状态变量、没有泄漏的处理程序、没有无意中删除处理程序,并且它适用于单击、选项卡或编程焦点。下面的代码和 jsFiddle -

$('#out').focus(function() 
    $(this).select();
);
$('#out').on('mousedown.selectOnFocus', function() 
    if (!($(this).is(':focus'))) 
        $(this).focus();
        $(this).one('mouseup.selectOnFocus', function(up) 
            up.preventDefault();
        );
    
);

https://jsfiddle.net/tpankake/eob9eb26/27/

【讨论】:

【参考方案5】:

创建一个bool。在焦点事件后将其设置为true,并在鼠标向上事件后将其重置。在鼠标上移的过程中,如果是true,则知道用户刚刚选择了文本字段;因此,您知道必须防止鼠标向上发生。否则,你必须让它过去。

var textFieldGotFocus = false;

$('#out').focus(function()

    $('#out').select();
    textFieldGotFocus = true;
);

$('#out').mouseup(function(e)

    if (textFieldGotFocus)
        e.preventDefault();
);

$(document).mouseup(function()  textFieldGotFocus = false; );

将重置变量的 mouseup 侦听器放在 document 上很重要,因为不能保证用户会在文本字段上释放鼠标按钮。

【讨论】:

谢谢!这激发了一个更简单的想法:而不是 document.mouseup 上的侦听器,只需在 out.mouseup 上将标志设置为 false:if(textFieldGotFocus) e.preventDefault(); textFieldGotFocus = false; 天哪。全局变量 + 事件处理 == 解决问题的方法。【参考方案6】:
onclick="var self = this;setTimeout(function() self.select();, 0);"

【讨论】:

这个答案启发了:$("#one").on('focus', null, function() var $that = $(this); setTimeout(function() $that.select(); , 0); );【参考方案7】:

在将焦点放在输入框之前选择文本。

$('#out').select().focus();

【讨论】:

【参考方案8】:

digitalfresh 的解决方案大部分都在那里,但有一个错误,即如果您使用 JS 手动触发 .focus()(因此不使用单击),或者如果您选择该字段,那么您会收到一个不需要的 mouseup 事件绑定 -这会导致第一次单击应取消选择要忽略的文本。

解决:

var out = $('#out');
var mouseCurrentlyDown = false;

out.focus(function () 
  out.select();

  if (mouseCurrentlyDown) 
    out.one('mouseup', function (e) 
      e.preventDefault();
    );  
  
).mousedown(function() 
  mouseCurrentlyDown = true;
);

$('body').mouseup(function() 
  mouseCurrentlyDown = false;
);

注意:mouseup 事件应该在 body 上而不是 input 上,因为我们要考虑用户在输入中的 mousedown-ing,将鼠标移出输入,然后 mouseup-ing。

【讨论】:

【参考方案9】:

tpankake 的答案转换为可重用的 jQuery 函数..(如果您对此表示赞同,也请对他的回答表示赞同)

在加载 jQuery 库后加载以下内容:

$.fn.focusSelect = function () 
    return this.each(function () 
        var me = $(this);
        me.focus(function () 
            $(this).select();
        );
        me.on('mousedown.selectOnFocus', function () 
            var me2 = $(this);
            if (me2.is(':focus') === false) 
                me2.focus();
                me2.one('mouseup.selectOnFocus', function (up) 
                    up.preventDefault();
                );
            
        );
    );
;

像这样使用它:

$(document).ready(function () 
    // apply to all inputs on the page:
    $('input[type=text]').focusSelect();

    // apply only to one input
    $('#out').focusSelect();
);

【讨论】:

以上是关于为 Chrome 选择焦点错误寻找更好的解决方法的主要内容,如果未能解决你的问题,请参考以下文章

隐藏许多选项时选择元素下拉菜单上的 Chrome 错误

如何防止在chrome中focus()上的文本选择

解决Chrome插件安装时出现的“程序包无效”问题亲测可用

最新版chrome浏览器安装Chrome插件时出现"CRX-HEADER-INVALID"解决方法

窗口/舞台失去焦点时的事件

寻找比在 Scriptable Objects 中使用字符串在别处调用特定方法更好的解决方案