【问题标题】:HTML / Javascript - stop left /right arrow from changing dropdown menu choiceHTML / Javascript - 从更改下拉菜单选项中停止左/右箭头
【发布时间】:2017-10-27 19:51:16
【问题描述】:

我正在创建一个带有输入网格的 Web 表单,用于在 Django 中创建对象。

似乎当焦点位于下拉菜单上时,向上和向左箭头选择上一项,向右/向下箭头选择下一项。

我想使用左/右箭头在网格上向左或向右移动焦点(有点像 excel)。我可以禁用左/右箭头更改菜单选项吗(同时保留上/下箭头的功能)?

【问题讨论】:

  • 谢谢,但它似乎不适用于 Firefox,只有 Chrome。
  • 我已经更新了 fiddle 以使用 firefox。我偶然发现了 Firefox 无法阻止默认行为的问题。我不适合 FF :(
  • 它似乎在我使用的版本中工作。感谢您的回复。

标签: javascript html drop-down-menu


【解决方案1】:

更改控件的默认行为有时会让用户感到沮丧。但其他时候,用户期望它像你的情况一样像 excel 一样工作:)

你可以这样做:

var selects = document.getElementsByTagName('select');
for (var i = 0; i < selects.length; i++){
    selects[i].addEventListener('keydown',function(e){    
        var key = e.which || e.keyCode;
        if(key == 37){
            var previousSibling = this.previousSibling;
            while(previousSibling && previousSibling.nodeType != 1) {
                previousSibling = previousSibling.previousSibling
            }
            previousSibling.focus();
            e.preventDefault();
        }else if(key === 39){
            var nextSibling = this.nextSibling;
            while(nextSibling && nextSibling.nodeType != 1) {
                nextSibling = nextSibling.nextSibling
            }
            nextSibling.focus();
            e.preventDefault();
        }
    })
}

键 37 = ,键 39 是
e.preventDefault(); 阻止您按下的键的默认行为。

Fiddle

【讨论】:

  • 我正在尝试将 excel 替换为数据上传工具,因此我需要模仿他们期望的功能。
  • 我在 Firefox 中遇到了更多问题。我最终使用 hack 来存储该值,并在焦点移动到下一个元素后将其设置回来。不是最好的,但它可以满足我的要求。
【解决方案2】:

虽然A1rPun's answer 执行了所要求的操作,但它在 Firefox 中不起作用。这是因为this Firefox bug,基本上event.preventDefault不会阻止&lt;select&gt;节点上的

解决方法

我针对这个问题做了一个解决方法,可以用来改进 A1rPun 的答案以支持 Firefox。

function ensurePreventDefault(select) {
    var selectedIndex, scrollTop;
    function saveState() {
        selectedIndex = select.selectedIndex;
        scrollTop = select.scrollTop;
    }

    saveState();
    if (!select.multiple && !select.size) {
        select.addEventListener('change', saveState);
    }

    // use setTimeout to wait a frame and see if the selected index was changed
    setTimeout(function () {
        select.removeEventListener('change', saveState);
        if (select.selectedIndex !== selectedIndex) {
            // Damn you, Firefox!
            select.selectedIndex = selectedIndex;
            select.scrollTop = scrollTop;
        }
    });
}

短版:存储selectedIndex 并在稍后恢复它。

长版:存储selectedIndex,以便我们稍后使用setTimeout检查它是否被Firefox更改。您还需要将这些值存储在 'change' 事件中以完全支持下拉菜单。同时存储scrollTop 以防止Firefox 在多选中滚动。它们呈现为列表,而不是下拉列表,导致 Firefox 在所选索引更改时向下或向上滚动。如果您确实不想想要收听它的'change' 事件,这将产生相反的效果。

用法

你可以这样使用它:

.addEventListener('keydown', function (event) {
    switch (event.which || event.keyCode) {
        case 37: // left arrow
        case 39: // right arrow
            event.preventDefault();
            ensurePreventDefault(this);
            break;
    }
});

JSFiddle

这扩展了 A1rPun 的 JSFiddle。

【讨论】:

  • 显然我对你投了反对票,但我完全不记得了。我什至不记得想过这个答案。一定是个错误。如果您稍微修改一下答案,我会很高兴地记住它(我希望这不会违反规则)
【解决方案3】:

Ruud's Answer 有效,但如果您仔细观察或在事件中运行大量代码,您会看到选择值更改下一个元素并返回到原始元素。

这是一个适用于 Firefox 的解决方案,对我来说看起来更干净。在其他浏览器中未经测试。

诀窍就是在 keydown 事件中将选择设置为禁用,然后在下一帧使用 setTimeout 重新启用它。在处理完事件处理程序中的所有代码之前,匿名函数不会运行,以确保不会过早重新启用选择。

mySelect.addEventListener('keydown', 
    function (event) {
        switch (event.which || event.keyCode || event.charCode) {
            case 33:
                this.disabled = true;
                setTimeout(function (elem) {elem.disabled = false;}, 0, this);
                break;

            case 34:
                this.disabled = true;
                setTimeout(function (elem) {elem.disabled = false;}, 0, this);
                break;
        }
    });

这是JSFiddle

【讨论】:

  • 我看到这会导致可怕的闪烁,因为 Opera 实际上会立即重新绘制元素。我做过的其他任何事情都没有这么快地触发重绘,但在这里我们有一个毫无意义的重绘干扰了一个荒谬的修复来解决 Firefox 中一个荒谬的错误。无论如何,我已经给了它一个赞成票,因为我确信我可以嗅出 Firefox 并定位这个修复......(就像我不得不嗅出 Opera 来解决一个同样奇怪的错误一样)。
  • 编辑:我也看到了 Firefox 闪烁,但不那么明显......在禁用它后将背景颜色设置为(在这种情况下)白色会进一步减少闪烁......并且为此的 CSS 规则可能会进一步减少它.
  • @DanielBeardsmore 我在 Firefox 中看不到任何闪烁。你在最新版本吗?你在 JSFiddle 上也看到这个闪烁吗?
  • 不,我在(64 位)Firefox ESR 上,因为即将到来的附加组件厄运(但仍然是 Windows 10 1709)。一开始我没有看到闪烁,所以它可能是间歇性的,并且可能取决于视频驱动程序,但是是的,它也存在于 JSFiddle 中。最新的 Opera 中的闪烁要严重得多(仍然只有几毫秒,但比 Firefox 中的多。)基本上您会看到控件变暗为禁用的背景颜色,然后返回到白色,可以使用 CSS 来控制。 --fake空白行--(裸键代码是JavaScript中需要常量的完美示例!!!)
  • @DanielBeardsmore 是的,它可能取决于视频驱动程序。我正在使用最新的 Beta 版,而且这种丑陋的修复效果非常好。这很难看,但恕我直言,比 Ruud 的前一个要少得多。我也没有在 Chrome 上看到任何闪烁,但是您的工作站可能比我的快很多。 ;)
【解决方案4】:

关于the answer of Ruud Lenders:仅当您在表单中有一个选择时才有效。如果您有多个选择下拉菜单,则可以使用以下版本:

$(document).on('keydown', 'select', function(event) {
    var value = $(this).find('option:selected').val();
    if ((event.which == 37 || event.which === 39)) {
        setTimeout(function (obj, val) {
            console.log(val)
                return function() {
                    obj.find('option[value="' + val + '"]').prop("selected", true)
                }
        }($(this), value), 0);
    }
});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-20
    • 1970-01-01
    相关资源
    最近更新 更多