23

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

4

12 回答 12

11

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

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

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

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

有趣的是,如果元素具有属性或>1 ,Chrome 中会触发事件。selectmultiplesize

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

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

于 2014-09-17T18:16:18.473 回答
6

更新

警告: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 来模拟选择可能是更清洁的方式。

于 2014-09-19T10:22:32.203 回答
3

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

由于问题是 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/

于 2014-09-17T14:20:47.183 回答
3

您的语法看起来不正确。

$("#target").keydown(function() {
    alert( "Handler for .keydown() called." );
});
于 2013-10-09T21:33:59.370 回答
2

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

keyup:当键盘上的键被释放时触发的事件。

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

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

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

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

我在这里有一个 plnkr 演示。

我已经在 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;
          });
        }
      });
    });
于 2014-09-19T18:05:00.387 回答
1

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

于 2014-09-13T15:34:04.540 回答
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>
于 2014-09-16T08:43:33.840 回答
1

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

请让我知道它是否适合您。

于 2014-09-18T09:07:53.300 回答
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;
        }
      }
    });
于 2014-09-20T09:22:23.723 回答
1

您好,由于没有关注具有 keydown 绑定的选择,因此无法正常工作

尝试这个

http://jsfiddle.net/t8fsuy33/

$('select').first().focus();
于 2014-09-18T20:17:49.943 回答
1

我找到了一个专门针对 Chrome 的非常独特的解决方案。It appears Chrome shifts outside the normal dom for select elements when they have focus so you never get the onkey(down|press|up) events to capture the keycode. 但是,如果选择框的大小大于 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,它将检测键码。我没有在其他任何地方看到这个答案,所以我想我会分享我的解决方案。

于 2015-11-12T21:40:31.070 回答
0

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

于 2017-02-27T20:56:15.393 回答