Событие keydown в выпадающем списке

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

В настоящее время я выполняю следующее:

$(document).on('keyup keydown', function (e) { shifted = e.shiftKey });
$(document).on('change', '.report_info select', function (e) {
    if (shifted) {
        //Code to change other drop down lists.
    }
});

Это работает, только если вы нажмете и удерживаете клавишу shift перед тем, как войти в раскрывающийся список. Если вы находитесь внутри DDL и нажмите клавишу shift, событие keyup/keydown не будет срабатывать, а shifted останется false

Есть ли способ поймать событие keyup/keydown, когда выпадающий список сфокусирован?

Edit:

Похоже, что это может быть проблема с Chrome, просто попробовал добавить следующее, и он работает в Firefox и IE, но не в Chrome:

$(document).on('keyup keydown', 'select', function (e) {
    shifted = e.shiftKey;
});

Вот скрипка, которая не работает в chrome: http://jsfiddle.net/ue6xqm1q/4

Ответы

Ответ 1

Я думаю, что ответ @judgeja может быть вашим лучшим выбором. Я отправляю это как "ответ" вместо комментария, потому что я провел собственное исследование, чтобы определить, что абсолютно ничего не запускается, когда элемент select открыт в Chrome.

Смотрите Fiddle: http://jsfiddle.net/m4tndtu4/6/

Я привязал все возможные обработчики событий (я думаю) к элементу input и обе элемента select.

В Chrome вы увидите много событий при работе с элементом input, но при первом открытии элемента select вы не увидите никаких событий.

Интересно, что события срабатывают в Chrome, если элемент select имеет атрибут multiple или size > 1.

В Firefox вы увидите события, запускающие все три элемента.

Вне предложения @judgeja, лучше всего будет имитировать элемент select.

Ответ 2

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

Поскольку проблема заключается в том, что хром не регистрирует события keydown/keyup на элементах select до тех пор, пока не исчезнет раскрывающийся список, нам нужно либо

a) выяснить, как сделать пожар события (я не знаю)

или

b) проверьте, соблюдены ли наши условия в другом порядке.

Chrome запустит событие нажатия клавиши shift после нажатия, поэтому мы можем просто проверить, был ли нажат клик непосредственно перед этим событием. Поскольку другие браузеры ведут себя более ожидаемо, мы также оставим прежний код на месте.

Для этого мы устанавливаем таймер в событии клика, а затем, когда событие shift для выбора будет запущено, если также был установлен только таймер события клика, мы должны запустить наш код здесь, чтобы хром его запустил. Мы reset таймер, чтобы он не срабатывал несколько раз.

ПРИМЕЧАНИЕ. Если вы нажмете shift сразу после установки значений (в любом пределе от указанного вами клика), он также установит их все. Я не думаю, что это необоснованно, поскольку на самом деле это кажется вполне естественным, когда это происходит.

Я использовал следующий код:

var shifted = false;
var hackytimer = 0;

$(document).on('keyup keydown', function (e) { 
    shifted = e.shiftKey;
});

$(document).on('keyup keydown', 'select', function (e) {
    shifted = e.shiftKey;
    if(Date.now() - hackytimer <200){
        changeAllSelects($(this).val());
    }
});

$(document).on('change', '.report_info select', function (e) {
    hackytimer = Date.now();        
    if (shifted) {
        changeAllSelects($(this).val());
    }
});

function changeAllSelects(cr){
    hackytimer = 0;
    $('.report_info select').each(function () {
        $(this).val(cr);
    });
}

См. рабочий пример здесь: http://jsfiddle.net/0fz5vcq6/2/

Ответ 3

UPDATE

Предупреждение: поведение Chrome (mis) отличается на разных платформах! В Chrome Windows событие keydown запускается сразу после выхода select, а на OsX - нет. Это объясняет, почему решение @judgeja работало для некоторых, и не для меня, в то время как мой работал на OsX, а не на Windows.

Итак, я создал обновленную скрипту, чтобы объединить мое решение OsX с его Windows.

http://jsfiddle.net/0fz5vcq6/5/

На платформах, где запускается keydown, используется решение @judgeja, если оно не запускается, оно проверяет событие keyup без предыдущего keydown (мое предыдущее решение). Это уродливо, поскольку оно работает только после RELEASE смены, но уродливое только на Chrome OsX.

var shifted = false;
var hackytimer = 0;
var lastval=null;

$(document).keydown(function(e){
    if(e.which == 16){
        if(Date.now() - hackytimer <200){
            alert("you pressed shift inside the select (Win)");
           changeAllSelects($(this).val());
       }        shifted = true;
    }
});

$(document).keyup(function(e){
    if(e.which == 16) {
        if(!shifted && lastval!=null) {

            alert("you pressed shift inside the select (OsX)");
            $('.report_info select').each(function () {
                changeAllSelects(lastval);
            });

        }
        shifted = false;
    }
});

$(document).on('change', '.report_info select', function (e) {
    hackytimer = Date.now();        
    if (shifted) {
        changeAllSelects($(this).val());
    } else {
        lastval=$(this).val();
    }
});

function changeAllSelects(cr){
    hackytimer = 0;
    $('.report_info select').each(function () {
        $(this).val(cr);
    });
}

Кредит в основном относится к @judgeja для своего решения таймера с некоторым дополнительным обходным решением для Mac (и других платформ, которые ведут себя одинаково)

Я все еще думаю, что эмулировать выборки с чем-то вроде HTML http://gregfranko.com/jquery.selectBoxIt.js/ является более чистым, так как они не должны вмешиваться в keydown/keyups.

ПРЕДЫДУЩАЯ РЕШЕНИЕ (только OsX)

Единственное решение, о котором я мог думать, в общем отсутствии какого-либо события, - проверить, произошло ли смещение без предыдущего сдвига. Это может работать, если у вас нет других элементов, которые ведут себя так же, как выбирает

http://jsfiddle.net/6jkkgx5e/

Это немного сложно и грязно, будет работать ПОСЛЕ того, как пользователь выпустит клавишу переключения

var shifted = false;
var lastval=null;

$(document).keydown(function(e){
    if(e.which == 16){
        shifted = true;
    }
});

$(document).keyup(function(e){
    if(e.which == 16){
        if(!shifted && lastval!=null) {

            alert("you pressed shift inside the select");
            $('.report_info select').each(function () {
                $(this).val(lastval);
            });

        }
        shifted = false;
    }
});

$(document).on('change', '.report_info select', function (e) {
    var cr = $(this).val();
    if (shifted) {
        $('.report_info select').each(function () {
            $(this).val(cr);
        });
    } else {
        lastval=cr;
    }
});

Должно вести себя нормально в браузерах без ошибок. Во всяком случае, я соглашаюсь с эмуляцией выбора с чем-то вроде HTML http://gregfranko.com/jquery.selectBoxIt.js/, возможно, более чистым способом.

Ответ 4

Ваш синтаксис выглядит некорректно.

$("#target").keydown(function() {
    alert( "Handler for .keydown() called." );
});

Ответ 5

Chrome hack: вы можете установить настраиваемое событие для документа. И активируйте это событие, когда нажмите клавишу shift внутри DDL. Триггер запуска JQuery может передавать пользовательские параметры.

Ответ 6

Проверьте рабочий JS FIDDLER

Попробуйте выполнить script для своего сценария

 <script type="text/javascript" language="javascript">
    window.shifted = false;
    $(document).on('keyup keydown', function (e) { shifted = e.shiftKey; });
    $(document).on('change', 'select.report_info', function (e) {
        var cr = $(this).val();
        if (shifted) {
            $('.report_info').each(function () {
                $(this).val(cr);
            });
        }
    });
</script>

Ответ 7

Bryan, вы можете попробовать следующий способ сделать это. Я тестировал Jsfiddle, что он работает на вашем пути. Если я правильно задал вопрос.

 var shifted = false;
$(document).on('keyup keydown', function (e) { shifted = e.shiftKey; });

$("select").on('keyup keydown',  function (e) {
    shifted = e.shiftKey;  
});
    $('.report_info select').on('change',  function (e) {
        var cr = $(this).val();
        if (shifted) {
            $('.report_info select').each(function () {
                $(this).val(cr);
            });
        }
    });

Пожалуйста, дайте мне знать, если это сработает для вас.

Ответ 8

Здравствуйте, это не сработало из-за того, что вы не сосредоточились на своем выборе, у которого есть ограничение на привязку

попробуйте это

http://jsfiddle.net/t8fsuy33/

$('select').first().focus();

Ответ 9

Прежде всего. Вы должны выбрать событие для регистрации. Не регистрируйтесь на клавиатуре и клавиатуре одновременно. Вы даете браузеру трудное время, потому что они влияют на ваш конечный результат. Чтобы понять, что я имею в виду, просто отредактируйте панель, добавьте событие keyup. Конечный результат ведет себя немного неаккуратно.

keyup. Событие запускается при отпускании клавиши на клавиатуре.

keydown. Событие запускается при нажатии клавиши на клавиатуре.

keypress: событие запускается при нажатии клавиши на клавиатуре.

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

Изменить. Быстрая заметка. Ключ для моего примера не очень хорошо работает, потому что кажется, что изменения в selectedIndex на первом месте, а затем связанное событие. При открытии ключа сначала запускается событие, работает ли оно, а затем изменяется выбранное значение. Чтобы играть с клавиатурой, приведенный ниже код нуждается в некоторой модификации, это означает, что шаг не требуется, когда вы используете keyup

У меня есть демо-версия plnkr здесь.

Я тестировал его на IE10, Opera, Safari, Firefox и Chrome. Как и следовало ожидать, браузеры webkit не запускают событие keydown/keyup/keypress, когда выбранный список имеет фокус. Причина, неизвестная мне, на данный момент. В Firefox отлично работает. На IE работает частично. Итак, чтобы достичь вашей цели, пользовательский код на помощь! Я только что связал событие изменения с документом, я слышу, как это произошло и изменилось. Если тип события изменяется, тогда применяется обходной путь. Вот код:

$(document).ready(function(){
    $(document).on('keydown change', 'select', function(evt){
        var shiftKey = evt.shiftKey;
        var code = evt.keyCode || evt.which;

        //if it a change event and i dont have any shiftKey or code
        //set the to a default value of true
        if(evt.type === 'change' && !shiftKey && !code){
          //special! only when change is fired
          shiftKey = true;
          code = true; 
        }

        //if shift key
        if(shiftKey && (code === 40 || code === 38 || code === true)){

          var target = $(evt.target);
          //if code is not true means it is not a change event, go ahead and set
          //a step value, else no step value
          var step = (code !== true) ? (code === 40) ? 1 : -1 : 0;
          var index = target[0].selectedIndex + step;

          //just to keep the lower and upper bound of the select list
          if(index < 0){
            index = 0;
          }else if(index >= target[0].length){
            index = target[0].length - 1;
          }

          //get all other select lists
          var allOtherSelects = target.closest('div').siblings('div').children('select');
          //foreach select list, set its selectedIndex
          $.each(allOtherSelects, function(i, el){
            el.selectedIndex = index;
          });
        }
      });
    });

Ответ 10

Перепрыгните эту вещь, помогите вам...:)

 var onkeydown = (function (ev) {
      var key;
      var isShift;
      if (window.event) {
        key = window.event.keyCode;
        isShift = window.event.shiftKey ? true : false;
      } else {
        key = ev.which;
        isShift = ev.shiftKey ? true : false;
      }
      if ( isShift ) {
        switch (key) {
          case 16: // ignore shift key
            break;
          default:
            alert(key);
            // do stuff here?
            break;
        }
      }
    });

Ответ 11

Я нашел очень уникальное решение этой проблемы специально для Chrome. Похоже, что Chrome перемещается за пределы обычного dom для избранных элементов, когда у них есть фокус, поэтому вы никогда не получите события onkey (down | press | up), чтобы захватить код ключа. Однако, если размер блока выборa > 1, то он работает. Но любой, кто хочет получить фактическое раскрывающееся поле вместо того, что похоже на поле со списком, может решить эту проблему с помощью этого кода. В моем случае я пытался предотвратить возврат ключа backspace к предыдущей странице браузера.

Javascript выглядит следующим образом:

      $(document).ready(function() { 
          $('select').keypress(function(event) 
             { return cancelBackspace(event) });
        $('select').keydown(function(event) 
           { return cancelBackspace(event) });
       }); 

      function cancelBackspace(event) {
         if (event.keyCode == 8) {
            return false;
          }
       }

Затем HTML выглядит так:

<select id="coaacct" style="border:none;width:295px;" onclick="if (this.size){this.size=''}else{this.size='20'};">

Я использую событие onclick, чтобы изменить размер поля выбора на 20, если он не имеет размера и не изменит его до нуля, если он имеет размер. Таким образом, он функционирует как раскрывающийся список обычного выбора, но поскольку он имеет размер больше 1, когда вы выбираете опцию, он обнаруживает коды ключей. Я не видел, чтобы это отвечало адекватно в другом месте, поэтому я решил поделиться своим решением.

Ответ 12

Если вам нужно сделать что-то с выпадающим списком, который является таким гранулированным, скорее всего, не стоит использовать собственный <select> элемент as-is. В этой теме отдельно обсуждаются многочисленные различия в реализации, и есть много больше, которые выходят за рамки этой дискуссии, но также могут повлиять на вас. Существует несколько JS-библиотек, которые могут обернуть этот элемент управления, оставив его как есть на мобильном телефоне (где собственно необходим нативный элемент управления), но эмулирует его на рабочем столе, где элемент управления на самом деле не делает многое, что нельзя эмулировать в JS.

  • bootstrap - автоматически не переносит собственный элемент управления для мобильных устройств
  • dropdown.js
  • dropdown.dot.js