捕捉回车键,但不要在选择浏览器自动完成建议时捕捉。

11

我在页面上有一些文本框,当用户在其中的任何一个文本框中按下回车键时,我想要点击一个链接。

使用JavaScript很容易捕获回车按钮(通过查找event.keyCodeevent.which中的13),但是当浏览器的自动完成功能启动并建议用户可能想要输入什么时,我遇到了一个问题。我们发现用户经常按回车键接受浏览器的建议,而不是按TAB键。这会使用户感到困惑,因为链接被立即点击,而他们仍然打算在其他某些字段中输入文本。

我知道最好在这里使用表单和提交按钮,但由于各种原因,这是不可行的。

我正在使用jQuery,因此可以提供jQuery解决方案。

10个回答

9

使用tuanvt在被接受的答案中提出的想法,我编写了一个能够完成任务的jQuery插件。

我跟踪用户按上下、PageUp和PageDown键的时间,以确定他们是否在自动完成框中。所有其他键都意味着他们已经离开了它。

我确保只对文本框应用这些规则:所有其他输入元素都会正常工作。

Opera已经非常好地实现了我想要实现的功能,所以我不会在该浏览器中强制执行我的规则 - 否则用户将不得不按两次Enter键。

在IE6、IE7、IE8、Firefox 3.5.5、Google Chrome 3.0、Safari 4.0.4、Opera 10.00中进行了测试。

它可以在jquery.com上作为SafeEnter插件下载。为了方便起见,发布1.0版本的代码如下:

// jQuery plugin: SafeEnter 1.0
// http://plugins.jquery.com/project/SafeEnter
// by teedyay
//
// Fires an event when the user presses Enter, but not whilst they're in the browser's autocomplete suggestions

//codesnippet:2e23681e-c3a9-46ce-be93-48cc3aba2c73
(function($)
{
    $.fn.listenForEnter = function()
    {
        return this.each(function()
        {
            $(this).focus(function()
            {
                $(this).data('safeEnter_InAutocomplete', false);
            });
            $(this).keypress(function(e)
            {
                var key = (e.keyCode ? e.keyCode : e.which);
                switch (key)
                {
                    case 13:
                        // Fire the event if:
                        //   - we're not currently in the browser's Autocomplete, or
                        //   - this isn't a textbox, or
                        //   - this is Opera (which provides its own protection)
                        if (!$(this).data('safeEnter_InAutocomplete') || !$(this).is('input[type=text]') || $.browser.opera)
                        {
                            $(this).trigger('pressedEnter', e);
                        }
                        $(this).data('safeEnter_InAutocomplete', false);
                        break;

                    case 40:
                    case 38:
                    case 34:
                    case 33:
                        // down=40,up=38,pgdn=34,pgup=33
                        $(this).data('safeEnter_InAutocomplete', true);
                        break;

                    default:
                        $(this).data('safeEnter_InAutocomplete', false);
                        break;
                }
            });
        });
    };

    $.fn.clickOnEnter = function(target)
    {
        return this.each(function()
        {
            $(this)
                .listenForEnter()
                .bind('pressedEnter', function()
                {
                    $(target).click();
                });
        });
    };
})(jQuery);

由于新插件网站的更改,您无法再从jquery获取此插件,但我注意到您已经将V1.0.1放在了上面(尽管我们可以访问它),这个版本有什么变化,您能发布一下吗? :) 谢谢 - GazB
对于任何试图在最新版本的jQuery(我认为是1.9+)中使其工作的人,.browser已经消失了,但是我无论如何都看不到Opera上的任何自动完成,因此只需从此行中删除最后一个检查即可: if (!$(this).data('safeEnter_InAutocomplete') || !$(this).is('input[type=text]') || $.browser.opera) 所以它应该改为: if (!$(this).data('safeEnter_InAutocomplete') || !$(this).is('input[type=text]')) - GazB

5

如果用户选择其中一个自动完成文本,他们总是需要按下键盘的向下箭头,那么为什么不在他们按下向下箭头时设置一个变量,然后如果之后他们按下Enter键,你再检查该变量。如果该变量被设置,你不应该执行链接点击功能,否则就像平常一样执行。


哇 - 这相当像希思·罗宾逊的作品,但我很喜欢!我猜我必须追踪其他按键(向上/向下/向上翻页/向下翻页,因为它们导航列表;还有其他返回键入的内容),并适当地设置/重置标志。我感觉到jQuery扩展的出现... - teedyay
请告诉我插件发布的时间,听起来需要大量按键追踪:D,祝好运。 - tuanvt
这是一个好主意。请记住,用户可能会在按下“向下”和“回车”键之间按下“向上”键。 - Prem
@tuanvt - 其实还不错!我已经将代码放在另一个回答中,但我会将你的回答标记为被采纳的,因为你真正做了艰苦的工作。希望你觉得有用! - teedyay
这假设用户使用键盘选择自动完成选项,而不是例如鼠标。 - twernt
是的,但用户选择鼠标时不会按回车键,对吧? - NotGaeL

3

JQuery很好用,但为什么不使用简单的JavaScript呢?

function submit_on_enter(e) {
    var keycode;
    if (window.event) keycode = window.event.keyCode;
    else if (e) keycode = (e.keyCode ? e.keyCode : e.which);
    else return true;

    if (keycode == 13) {
        if (window.previousKeyCode) {
            // down=40,up=38,pgdn=34,pgup=33
            if (window.previousKeyCode == 33 || window.previousKeyCode == 34 ||
                window.previousKeyCode == 39 || window.previousKeyCode == 40) {
                    window.previousKeyCode = keycode;
                    return true;
            }
        }
        submit_form();
        return false;
    } else {
        window.previousKeyCode = keycode;
        return true;
    }
}

3

尝试在复选框上关闭自动完成功能,虽然这不是所有浏览器的标准,但它适用于常见的浏览器。

<input type="text" autocomplete="off" />

1
失去自动完成功能将是一件遗憾的事情。 - teedyay

2
这对我有效:
$('input').keypress(function(e) {
    if(e.which == 13) {
        if(this.value)
        {
            $("#submitbutton").click();
        }
    }
});

2

在keyup事件中追踪回车键,当你检测到keyup事件中的回车键时,选择操作已经完成。

在keydown事件中检测回车键并执行操作会干扰自动完成功能。


1
如果您正在使用新的HTML5表单字段类型,您可能希望按照以下方式更改teedyay的代码:
case 13:
                    // Fire the event if:
                    //   - we're not currently in the browser's Autocomplete, or
                    //   - this isn't a textbox, or
                    //   - this is Opera (which provides its own protection)
                    if (!$(this).data('safeEnter_InAutocomplete') || !$(this).is('input([type=text],[type=email],[type=number],[type=search],[type=tel],[type=url])') || $.browser.opera)
                    {
                        ...

请注意新的输入类型。


0

另一种(更安全)的方法是使用 keyupkeydown 事件来检测值的变化。

自动完成在 keyDown 事件之后设置值。当观察到这两个事件时,以下解决方案比其他解决方案更可靠:

var tempValue;
// fire when enter is 1. pressed and 2. released
function handlerEnter(type){
     // save the value for comparison
     if(type == 'keyDown'){
         tempValue = document.activeElement.value;
         return null; // quit
     }

     // quit when the value changed in between keyDown & keyUp
     if(type == 'keyUp' && tempValue != document.activeElement.value){
         return null;
     }

     // autocomplete wasn't used
     doStuff();
}

你可能想要检查一下 document.activeElement 是否是一个输入框。随意使用 我的邪恶原型扩展


0

我不确定您是否在窗口或特定的DOM元素上捕获按键事件。 您应该使用后者(例如,在form元素上),然后在事件处理程序中查看事件对象,以确定事件的起源是哪个DOM元素。 如果这是一个带有自动完成的文本字段,则为 return false;

查看jQuery的.keypress()事件处理程序和事件对象的event.target属性。


在找到用户按下回车键时具有焦点的文本输入后,我如何确定浏览器是否在使用自动完成功能? - teedyay
我猜您不能将任何与自动完成相关的文本字段视为不适用于提交表单的选项?如果不是,那么您可以结合@tuanvt的建议,捕获按键顺序,以确定何时按下“向下”箭头(可能后跟“向上”箭头)。 - Prem
无论如何,针对表单而不是窗口进行定位是个好主意,因为这有助于减少后期开发中的冲突机会。 - Prem
嗨,谁给这个建议点了踩?能否分享一下你为什么觉得它没有帮助? - Prem
我给你点了个踩。我想知道如何检测用户在按下回车键时是否在浏览器的自动完成建议中:你的答案没有帮助我如何做到这一点。你的答案告诉我如何找到用户在按下回车键时所在的元素,然后说“如果这是一个带有自动完成功能的文本字段...”,但没有告诉我如何找到这些信息,这正是我的问题所在。 - teedyay
好的,谢谢您的回复。我假设您知道哪个表单字段适合自动完成。很酷,很酷。 - Prem

0

我遇到了同样的问题,虽然不完美,但我使用了另一种方法,我认为更简单。在创建自动完成时,我为选择事件设置当前时间,然后在执行任何操作之前进行比较:

$('#completer').autocomplete({
  source: ['First', 'Last'], delay: 0, minLength: 0,
  select: function(ev, ui) {
    $(ev.target).data('lastAutocompleteSelectTimestamp', new Date().getTime())
  }
})

$(document).on('keydown', '#completer', function(ev){
  if (ev.which != 13) return
  var lastAutocompletionTime = $(ev.currentTarget).data('lastAutocompleteSelectTimestamp')
  if (!lastAutocompletionTime || (new Date().getTime() - lastAutocompletionTime) > 100)
    alert('Enter pressed outside autocomplete context')
})
<html>
<head>
  <link href="https://code.jquery.com/ui/1.11.0/themes/smoothness/jquery-ui.css" rel="stylesheet"/>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
  <script src="https://code.jquery.com/ui/1.11.0/jquery-ui.min.js"></script>
</head>
<body>
  <input id=completer type=text />
</body>
</html>


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