Перехватывать клавишу ввода, но не при выборе предложения автозаполнения браузера - PullRequest
11 голосов
/ 30 октября 2009

У меня есть несколько текстовых полей на странице, и я хочу щелкнуть ссылку, когда пользователь нажимает, введите любой из них.

Я могу легко перехватить кнопку ввода, используя javascript (ища 13 в event.keyCode и event.which), но я столкнулся с проблемой, когда включилась функция автозаполнения браузера и подсказала, что пользователь может захотеть набрать. Мы обнаруживаем, что пользователи часто нажимают ввод, чтобы принять предложение браузера, а не вкладку. Это сбивает с толку пользователей, так как ссылка нажимается сразу, тогда как они по-прежнему предназначены для ввода текста в некоторые другие поля.

Я знаю, что здесь было бы лучше использовать форму и кнопку отправки, но по разным причинам это нецелесообразно.

Я использую jQuery, поэтому не стесняйтесь предлагать решения jQuery.

Ответы [ 10 ]

9 голосов
/ 18 ноября 2009

Используя идею tuanvt в принятом ответе, я написал плагин jQuery, который делает эту работу.

Я отслеживаю, когда пользователь нажимает клавиши «вверх», «вниз», «вверх» и «вниз», чтобы определить, когда они находятся в окне автозаполнения. Все остальные ключи подразумевают, что они оставили его.

Я гарантирую, что мы применяем эти правила только к текстовым полям: все остальные элементы ввода ведут себя нормально.

Opera уже довольно хорошо справляется со своими задачами, поэтому я не применяю свои правила в этом браузере - иначе пользователю придется дважды нажать клавишу ввода.

Протестировано в 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);
5 голосов
/ 30 октября 2009

Пользователь всегда должен нажимать клавишу «Вниз», если он выбирает один из вариантов автоматического завершения текста, почему бы не установить переменную на что-либо, когда он нажимает клавишу «Вниз», а затем, если он делает ввод, впоследствии вы проверяете переменная. Вы не должны выполнять функцию щелчка по ссылке, если переменная установлена, иначе делайте это как обычно.

3 голосов
/ 02 июня 2012

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 голосов
/ 30 октября 2009

Попробуйте отключить автозаполнение на вашем флажке, хотя это не является стандартным для всех браузеров, но работает в обычных браузерах.

<input type="text" autocomplete="off" />
2 голосов
/ 06 сентября 2012

Это работает для меня:

$('input').keypress(function(e) {
    if(e.which == 13) {
        if(this.value)
        {
            $("#submitbutton").click();
        }
    }
});
2 голосов
/ 14 июля 2011

отслеживание нажатия клавиши ввода для события keyup, выбор завершается к тому времени, когда вы обнаружите клавишу ввода для события keyup.

обнаружение клавиши ввода при нажатии и выполнение операции мешает работе автозаполнения.

1 голос
/ 23 апреля 2012

Если вы используете новые типы полей формы 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 голосов
/ 21 июля 2016

Другой (более безопасный) подход заключается в использовании событий keyup и keydown для обнаружения изменений значения.

Автозаполнение устанавливает значение после события 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 голосов
/ 10 октября 2014

Я столкнулся с той же проблемой, и, хотя она не была идеальной, я использовал другой подход, который я считаю более простым. При создании автозаполнения я устанавливаю текущее время для события выбора, а затем сравниваю его, прежде чем предпринимать какие-либо действия:

$('#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>
0 голосов
/ 30 октября 2009

Я не уверен, что вы отслеживаете нажатия клавиш в окне или на определенных элементах DOM. Вы должны сделать последнее (например, для элемента form), а затем в своем обработчике событий посмотреть на объект события, чтобы определить, какой элемент DOM был источником события. Если это текстовое поле с автозаполнением, то return false;.

Посмотрите на обработчик событий jQuery .keypress() и свойство event.target объекта события.

...