下拉列表中的keydown事件

时间:2013-10-04 14:25:01

标签: javascript jquery html google-chrome

我正在尝试创建一个下拉列表,当用户持有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

12 个答案:

答案 0 :(得分:9)

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

请参阅小提琴:http://jsfiddle.net/m4tndtu4/6/

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

在Chrome中,您在使用input元素时会看到很多事件,但是当您在第一个select元素中工作时,您将看不到任何事件触发开。

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

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

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

答案 1 :(得分:6)

<强>更新

警告:Chrome(mis)行为在不同平台上有所不同!在Chrome Windows中,keydown事件在select发布后立即触发,而在OsX上则不是。这解释了为什么@judgeja解决方案适用于某些人,而且对我来说没有用,而我的工作是在OsX而不是在Windows上工作。

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

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

在触发keydown的平台上使用@judgeja解决方案,如果没有触发,它会测试没有先前keydown的keyup事件(我以前的解决方案)。这很丑,因为它仅在Shift键的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(以及行为相同的其他平台)增加了一些解决方法

我仍然认为使用像http://gregfranko.com/jquery.selectBoxIt.js/这样的HTML来模拟选择更清晰,因为它们不应该干扰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;
    }
});

应该在非错误的浏览器上正常运行。无论如何,我同意用http://gregfranko.com/jquery.selectBoxIt.js/之类的HTML来模拟选择可能是更清洁的方式。

答案 2 :(得分:3)

您的语法看起来不正确。

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

答案 3 :(得分:3)

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

由于问题是chrome没有在select元素上注册keydown / keyup事件,直到下拉列表消失之后,我们需要

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

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

Chrome会在点击后触发shift按键事件,因此我们只需检查是否在此事件发生前立即按下了click。由于其他浏览器表现得更加出色,我们也会保留以前的代码。

要做到这一点,我们在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/

答案 4 :(得分:2)

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

keyup :在键盘上释放键时触发了事件。

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

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

他们有差异,更好地坚持一个,我更喜欢这个例子使用keydown,只是和我玩得更好,你可以使用keyup。

修改:快速说明。我的示例的关键字效果不佳,因为看起来,selectedIndex中的更改首先出现,然后是绑定事件。在keydown上,首先触发事件,它是否正常工作然后selectedIndex发生变化。要使用keyup,下面的代码需要进行一些修改,这意味着当你使用keyup时不需要这个步骤

我有一个plnkr演示here

我在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'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;
          });
        }
      });
    });

答案 5 :(得分:1)

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

答案 6 :(得分:1)

检查工作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>

答案 7 :(得分:1)

布莱恩 你可以尝试以下方式来做到这一点。我在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 :(得分:1)

您好,因为没有关注具有keydown bound

的select

试试这个

http://jsfiddle.net/t8fsuy33/

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

答案 9 :(得分:1)

跳这个东西可以帮助你.. :)

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

答案 10 :(得分:1)

我发现了一个针对此问题的非常独特的解决方案。如果选择元素具有焦点,则Chrome会在正常dom之外移动,因此您永远不会获得onkey(down | press | 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看起来像这样:

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

我使用onclick事件将选择框的大小更改为20(如果没有大小),如果它有大小则将其更改为空。这样,它的功能类似于普通的选择下拉列表,但是当您选择该选项时,它的大小大于1,它将检测键码。我没有在其他任何地方看到这个问题,所以我想我会分享我的解决方案。

答案 11 :(得分:0)

如果您需要使用详细信息的下拉列表进行操作,那么使用原生<select>元素可能不值得。仅在此线程中,讨论了许多实现差异,并且还有许多不在本讨论范围之内,但也可能会影响您。有几个JS库可以包装这个控件,将其保留在移动设备上(实际需要本机控件),但在桌面上进行仿真,控件并没有真正做很多事情。用JS模拟。