为什么这个文本区域不会在使用 .focus() 后聚焦?

54

当用户点击“回复”按钮时,我有这段代码用于聚焦文本区域:

    $('#reply_msg').live('mousedown', function() {
        $(this).hide();
        $('#reply_holder').show();
        $('#reply_message').focus();
    });
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.4.3/jquery.min.js"></script>
<div id="reply_msg">
      <div class="replybox">
      <span>Click here to <span class="link">Reply</span></span>
      </div>
      </div>
      <div id="reply_holder" style="display: none;">
      <div id="reply_tab"><img src="images/blank.gif" /> Reply</div>
      <label class="label" for="reply_subject" style="padding-top: 7px; width: 64px; color: #999; font-weight: bold; font-size: 13px;">Subject</label>
      <input type="text" id="reply_subject" class="input" style="width: 799px;" value="Re: <?php echo $info['subject']; ?>" />
      <br /><br />
      <textarea name="reply" id="reply_message" class="input" spellcheck="false"></textarea>
      <br />
      <div id="reply_buttons">
      <button type="button" class="button" id="send_reply">Send</button>
      <button type="button" class="button" id="cancel_reply_msg">Cancel</button>
      <!--<button type="button" class="button" id="save_draft_reply">Save Draft</button>-->
      </div>
    </div>

它显示了回复表单,但是文本区域不会聚焦。我是通过AJAX添加文本区域的,这就是为什么我使用.live()的原因。我添加的框(甚至通过AJAX添加#reply_msg并在其上按下鼠标时有反应),但它不会聚焦在文本区域上。

5个回答

59

单击可聚焦元素会按照以下顺序引发事件:

  1. mousedown
  2. focus
  3. mouseup
  4. click

因此,这里是正在发生的事情:

  1. mousedown<a> 引发
  2. 您的事件处理程序尝试将焦点放在 <textarea>
  3. mousedown 的默认事件行为尝试将焦点放在 <a> 上(这将从 <textarea> 中取得焦点)

这里有一个演示,说明了这种行为:

$("a,textarea").on("mousedown mouseup click focus blur", function(e) {
  console.log("%s: %s", this.tagName, e.type);
})
$("a").mousedown(function(e) {
  $("textarea").focus();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a href="javascript:void(0)">reply</a>
<textarea></textarea>

那么,我们如何解决这个问题呢?

使用 event.preventDefault() 来阻止 mousedown 的默认行为:

$(document).on("mousedown", "#reply_msg", function(e) {
    e.preventDefault();
    $(this).hide();
    $("#reply_message").show().focus();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a href="javascript:void(0)" id="reply_msg">reply</a>
<textarea id="reply_message"></textarea>


我已经在做这个了,但它并没有起作用,不过还是谢谢你的回答 :) - Nathan
1
哦,是的,“mouseup”确实有效 - 而且没有任何超时。谢谢 :) - Nathan
我知道这个答案发布已经有几年了。我正在寻找关于事件触发顺序的信息,例如:mousedownfocusmouseupclick。@canon,你能分享一下你从哪里得到的吗?我在规范的任何部分都找不到它: https://www.w3.org/TR/uievents/#events-focusevent-event-order, https://www.w3.org/TR/uievents/#legacy-uievent-event-order, https://www.w3.org/TR/uievents/#events-mouseevent-event-order - ScriptyChris
@Chris92 测试和观察。 - canon
这不是标准化的浏览器行为,是吗?我希望在规范中能找到这个东西。 - ScriptyChris

36

从事件处理程序中聚焦于某些内容本身是授予焦点的,这总是有问题的。一般的解决方案是在超时之后设置焦点:

setTimeout(function() {
  $('#reply_message').focus();
}, 0);

这样可以让浏览器自己做它该做的事情,然后你再把焦点移到你想要的地方。


7
为什么要使用超时,而不是一开始就使用适当的事件呢? - canon
2
@antisanity - 很好的观点,如果这正是OP真正感兴趣的。也就是说,如果对于这个特定情况,“mouseup”事件与“mousedown”一样适用于所需的交互。 - Pointy
1
@canon 因为这个解决方案适用于除了 OP 特定情况之外的其他情况。 - Michael Jess
1
为什么它“总是有问题”? - Piper

4
今天我遇到了一个问题,与 jQuery UI (v1.11.4) 中的一个 bug 有关。该 bug 导致在可拖动/可放置的元素内部的 textarea 元素在接收到焦点点击之前停止默认点击行为。
解决方法是重新设计 UI,使得 textarea 不再出现在可拖动元素内部。
这是一个特别难以调试的问题,因此我在这里留下答案,以便其他人发现并受益。

4

这可能与这个问题相同吗?jQuery Textarea focus

尝试在 .show() 完成后调用 .focus()

$('#reply_msg').live('mousedown', function() {
    $(this).hide();
    $('#reply_holder').show("fast", function(){
        $('#reply_message').focus();
    }); 
});

0

这可能也与浏览器有关。我正在使用Vue进行项目开发,在Chrome(v101)中,textarea上的el.focus()可以正常工作,但在Firefox(v100.0)中无法正常工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接