【问题标题】:keydown event in drop down list下拉列表中的 keydown 事件
【发布时间】:2013-10-11 14:22:34
【问题描述】:

我正在尝试创建一个下拉列表,当用户按住 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 事件?

编辑:

看起来这可能只是 Chrome 的问题,刚刚尝试添加以下内容,它适用于 Firefox 和 IE,但不适用于 Chrome:

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

这是它在 chrome 中无法使用的小提琴:http://jsfiddle.net/ue6xqm1q/4

【问题讨论】:

  • 您是否尝试将触发器添加到
  • 以上代码正在使用铬。使用 jquery 模糊。这可能会解决您的问题
  • 您知道 chrome 问题跟踪器上的错误在哪里吗?
  • 我从未将其报告为错误,不确定是否存在。

标签: javascript jquery html google-chrome


【解决方案1】:

我认为@judgeja 的回复可能是您最好的选择。我将其发布为“答案”而不是评论,因为我已经完成了自己的研究,以确定在 Chrome 中打开 select 元素时绝对不会触发任何事件。

见小提琴:http://jsfiddle.net/m4tndtu4/6/

我已将所有可能的事件处理程序(我认为)附加到 input 元素和 select 元素。

在 Chrome 中,使用 input 元素时会触发许多事件,但在打开第一个 select 元素时不会触发任何事件。

有趣的是,如果 select 元素具有 multiple 属性或 size>1,则事件 do 在 Chrome 中触发。

在 Firefox 中,您会看到在所有三个元素上触发的事件。

在@judgeja 的建议之外,您最好的选择可能是模拟select 元素。

【讨论】:

    【解决方案2】:

    更新

    警告:Chrome(错误)行为在不同平台上有所不同!在 Chrome Windows 中,在释放选择后立即触发 keydown 事件,而在 OsX 中则不会。这就解释了为什么 @judgeja 解决方案对某些人有效,而对我无效,而我的解决方案在 OsX 上工作而不是在 Windows 上。

    所以我创建了一个更新的小提琴来将我的 OsX 解决方案与他的 Windows 解决方案合并。

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

    在触发 keydown 的平台上使用@judgeja 解决方案,如果没有触发它,它会在没有之前的 keydown 的情况下测试 keyup 事件(我之前的解决方案)。它很丑,因为它仅在释放 shift 键后才有效,但仅在 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(和其他行为相同的平台)添加了一些解决方法

    我仍然认为使用像 http://gregfranko.com/jquery.selectBoxIt.js/ 这样的 HTML 来模拟选择更干净,因为它们不应该干扰 keydown/keyups。

    以前的解决方案(仅限 OsX)

    在完全没有任何事件的情况下,我能想到的唯一解决方案是测试在没有上一次降档的情况下是否发生了升档。如果您没有其他与选择行为方式相同的元素,这可能会起作用

    http://jsfiddle.net/6jkkgx5e/

    这有点棘手和肮脏,在用户释放 shift 键后才能工作

    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;
        }
    });
    

    应该在没有问题的浏览器上正常运行。无论如何,我同意使用像http://gregfranko.com/jquery.selectBoxIt.js/ 这样的 HTML 来模拟选择可能是更简洁的方式。

    【讨论】:

    • @judgeja 是的,Chrome 37.0.2062.120 OsX,你能指定它是如何不工作的吗? (给出错误,不更新,...)
    • 我使用的是 chrome 37.0.2062.120 m,但它没有按照 OP 的要求工作。如果单击下拉列表,然后按住 shift,然后选择一个选项,则仅更改当前的下拉列表。
    • @judgeja 不是在您释放 shift 键时触发的更新(和警报)吗?您是在尝试小提琴还是复制代码? “37.0.2062.120 m”中的“m”代表什么?
    • 不,它没有被触发。我正在尝试小提琴。我不知道 m 代表什么,它是 Windows 8 的最新版本。
    • @judgeja 好的,显然 Windows 上的 Chrome 在您释放选择后会触发一个 keydown 事件,这使您的解决方案在 Windows 上工作但在 Mac 上不起作用(并且我对 keyup 的测试失败),而 Chrome 操作系统X 没有,这使我的解决方案可以在 Mac 上运行,但不能在 Windows 上运行。将两者合并将使其适用于两者。
    【解决方案3】:

    您的语法看起来不正确。

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

    【讨论】:

    • $(document).on(event,selector,function) 适用于页面加载后动态添加的元素,这是我需要的。
    【解决方案4】:

    老实说,这是一个相当老套的解决方案,但它是达到目的的一种手段,直到你希望找到更好的东西。

    由于问题是 chrome 在下拉列表消失之前不会在 select 元素上注册 keydown/keyup 事件,因此我们需要

    a) 弄清楚如何让事件触发(我不知道)

    b) 检查我们的条件是否以不同的顺序得到满足。

    Chrome 将在点击后触发 shift keypress 事件,因此我们可以简单地检查在此事件之前是否立即按下了点击。由于其他浏览器的行为更符合预期,我们也将保留之前的代码。

    为此,我们在 click 事件上设置了一个计时器,然后当触发 select 的 shift 事件时,如果也刚刚设置了 click 事件计时器,我们应该在此处运行我们的代码,以便 chrome 触发它。然后我们重置计时器,使其不会被多次触发。

    注意:如果您在设置值后立即按 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/

    【讨论】:

      【解决方案5】:

      首先。您应该选择要注册的活动。不要同时注册 keyup 和 keydown。您给浏览器带来了麻烦,因为它们会影响您的最终结果。要明白我的意思,只需编辑 plunk,添加一个 keyup 事件。最终结果表现得有点草率。

      keyup:在键盘上释放一个键时触发的事件。

      keydown:在键盘上按下某个键时触发的事件。

      keypress:在键盘上按下某个键时触发的事件。

      它们各有不同,最好坚持一个,我更喜欢这个例子使用keydown,只是和我玩得更好,你可以使用keyup。

      编辑:快速注释。我的示例的 keyup 效果不佳,因为似乎 selectedIndex 中的更改首先出现,然后是绑定事件。在 keydown 上,首先触发事件,它是否有效,然后 selectedIndex 更改。要玩keyup,下面的代码需要一些修改,也就是说当你使用keyup时不需要这一步

      我有一个 plnkr 演示 here

      我已经在 IE10、Opera、Safari、Firefox 和 Chrome 上测试过它。如您所料,webkit 浏览器在选择列表具有焦点时不会触发 keydown/keyup/keypress 事件。目前,我不知道原因。在 Firefox 中效果很好。在 IE 上部分工作。所以,为了实现你的目标,自定义代码来拯救你!我刚刚将一个更改事件绑定到文档,我听到了 kewdown 和更改。如果事件类型发生变化,那么解决方法就会发挥作用。这里有一些代码:

      $(document).ready(function(){
          $(document).on('keydown change', 'select', function(evt){
              var shiftKey = evt.shiftKey;
              var code = evt.keyCode || evt.which;
      
              //if it's 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;
                });
              }
            });
          });
      

      【讨论】:

      • 我捕捉到了 keyup 和 keydown 事件,因为它改变了 'shifted' 变量。如果我只捕捉到 keydown 事件,shifted 将永远是真的。在您的示例中,无论是否按住 SHIFT,我都看到所有下拉列表都发生了变化。
      • 哦,是的,抱歉,我似乎没有测试过那个场景。我尝试了许多解决方案,但无法达到您的目标。好像是浏览器的问题。一种解决方法是在没有更改事件的情况下使用我上面的代码,但是当您选择一个选项并且列表具有焦点时(也就是下拉列表可见),您的列表不会改变。另一种解决方法是在列表选项上注册单击事件,然后也更改其他选项。这仅适用于 webkit 浏览器。我已经在上面的帖子中编辑了 plunker url。祝你好运!
      【解决方案6】:

      Chrome hack:您可以为文档设置自定义事件。并在 DDL 中按下 shift 键时触发此事件。 Jquery 触发触发器可以传递自定义参数。

      【讨论】:

      • 这样做的问题是 DDL 的更改事件将在自定义事件之前运行:shifted.ddl。见这里:jsfiddle.net/t8vep3jn 我可以运行需要在自定义事件中完成的代码,但是对于 Firefox 和 IE,它会在每次按下 shift 时运行,而不仅仅是在 shift+click 上运行。
      • 只有在进入下拉列表之前按住 shift 键才有效。
      • @Bryan 嗯。您可以向我展示(不工作)您需要的 jsfiddle 示例吗?我想我不完整或误解你。但我想帮助你。
      • @Deep 我在原始问题的末尾添加了一个小提琴。如果您在打开下拉列表之前按住 shift,这将有效。我正在寻找一种解决方案,以便在您打开下拉列表后按 shift 时使其正常工作。
      【解决方案7】:

      检查工作的JS FIDDLER

      为您的场景尝试以下脚本

       <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>
      

      【讨论】:

      • 我看不出这与我尝试的有什么不同,你能解释一下吗?
      • 我只是将选择器从 .report_info select 更改为 select.report_info 并且它也在 chrome 上工作。试试提琴手js fiddler
      • 您在点击下拉列表之前是否按住 shift 键?如果是这样,那以前是有效的。当下拉列表展开时,我试图捕捉 shift 事件。
      • 这两种情况都适用于我的情况。你试过DEMO
      • 我有,但我仍然遇到这个问题。我认为这可能与某些扩展发生冲突,但我在 Windows 7 上使用了全新安装的 chrome,但它仍然无法正常工作。您运行的是什么版本和操作系统?
      【解决方案8】:

      布莱恩, 您可以尝试以下方式来做到这一点。我在 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);
                  });
              }
          });
      

      如果它适合你,请告诉我。

      【讨论】:

      • 这真的对其他投票的人有用吗?它对我不起作用:jsfiddle.net/5fnht2t6
      • Bryan,我刚刚更新了一行代码。所以请在这里尝试,如果您仍有任何问题,请告诉我..jsfiddle.net/5fnht2t6/1
      • Bryan 很清楚他的问题只出在 chrome 上,而您的小提琴与 chrome 中的原件有同样的问题..
      • 不适合我,Chrome 37 OsX,所以显然不同版本/平台上有不同的 Chrome 功能,所以要小心测试很多
      【解决方案9】:

      你好,因为没有关注你的选择,它有 keydown 绑定,所以没有工作

      试试这个

      http://jsfiddle.net/t8fsuy33/

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

      【讨论】:

      • 是的,我使用的是 Ubuntu 12 + Chrome 34.0.1847.116
      【解决方案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 的非常独特的解决方案。当它们具有焦点时,它出现了普通DOM以外的Chrome Shifts for Select Element,因此您永远不会获取Onkey(upd | up |)事件以捕获密钥码。但是,如果选择框的大小大于 1,则它可以工作。但是任何想要一个实际的下拉框而不是看起来像组合框的人都可以用这段代码解决这个问题。就我而言,我试图阻止退格键返回上一个浏览器页面。

        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 看起来像这样:

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

        如果没有大小,我使用 onclick 事件将选择框的大小更改为 20,如果有大小,则将其更改回无。这样,它的功能就像普通的选择下拉菜单一样,但是因为当您选择选项时它的大小大于 1,它将检测键码。我没有在其他任何地方看到这个问题得到充分回答,所以我想我会分享我的解决方案。

        【讨论】:

        • 嗨!使用 oracle jet 和组合框(oj-combobox-one),以及输入(文本和数字),如果我们使用 keydown,它可以完美运行!感谢您的提示:)
        【解决方案12】:

        如果您需要使用如此精细的下拉菜单来执行操作,那么按原样使用本机 &lt;select&gt; 元素可能不值得。仅在这个线程中,就讨论了许多实现差异,还有很多超出了本讨论范围但也可能影响您的内容。有几个 JS 库可以包装此控件,将其保留在移动设备上(实际上需要本机控件),但在桌面上模拟它,该控件实际上并没有做太多无法在 JS 中模拟的事情.

        【讨论】:

          猜你喜欢
          • 2021-01-23
          • 1970-01-01
          • 2014-03-27
          • 1970-01-01
          • 2011-06-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-10-05
          相关资源
          最近更新 更多