如何避免使用 Javascript 在多选框中进行 ctrl-click 的需要?

Posted

技术标签:

【中文标题】如何避免使用 Javascript 在多选框中进行 ctrl-click 的需要?【英文标题】:How to avoid the need for ctrl-click in a multi-select box using Javascript? 【发布时间】:2012-01-28 07:53:46 【问题描述】:

我认为这将是一个简单的 hack,但我现在已经搜索了几个小时,但无法找到正确的搜索词。我想要一个普通的多选框(<select multiple="multiple">),但我不希望用户必须按住控制键才能进行多选。

换句话说,我希望左键单击以切换光标下的<option> 元素,而不更改任何其他元素。换句话说,我想要一个看起来像组合列表框但行为像一组复选框的东西。

任何人都可以提出一个简单的方法来用 javascript 做到这一点吗?谢谢。

【问题讨论】:

如果你不介意改变你的标记,你可以建立一个复选框和标签列表,然后隐藏复选框,并设置标签的样式(当它被选中时)具有相似的视觉外观到<select multiple>。 Demo in fiddle 【参考方案1】:

检查这个小提琴:http://jsfiddle.net/xQqbR/1022/

您基本上需要为每个<option> 覆盖mousedown 事件并在那里切换selected 属性。

$('option').mousedown(function(e) 
    e.preventDefault();
    $(this).prop('selected', !$(this).prop('selected'));
    return false;
);

为简单起见,我在上面给出了“选项”作为选择器。您可以对其进行微调以匹配特定 <select> 元素下的 <option>s。例如:$('#mymultiselect option')

【讨论】:

你可以在那里使用! this.selected 这依赖于 jQuery。请确保在加载 DOM 元素并准备好绑定到事件后执行上述代码。放置它的好地方是您的$(document).ready(...) 无法正常工作。一旦你拖动鼠标,它就会取消选择所有选项。 非常好的解决方案。我注意到的唯一缺点是事件预防以父选择不关注的方式工作,从而导致不同的外观和感觉(灰色而不是所选选项的蓝色背景)。为了保持外观和感觉,我手动专注于选择框。 $(this.parentElement).focus(); 正如其他人所说,为了简化它只是this.selected = !this.selected; 真的没有必要使用jQuery【参考方案2】:

必须自己解决这个问题,并注意到bugged behavior a simple interception of the mousedown 和设置属性会有,所以覆盖了 select 元素并且效果很好。

jsFiddle: http://jsfiddle.net/51p7ocLw/

注意:此代码确实通过替换 DOM 中的选择元素来修复错误行为。这有点激进,并且会破坏您可能附加到元素的事件处理程序。

window.onmousedown = function (e) 
    var el = e.target;
    if (el.tagName.toLowerCase() == 'option' && el.parentNode.hasAttribute('multiple')) 
        e.preventDefault();

        // toggle selection
        if (el.hasAttribute('selected')) el.removeAttribute('selected');
        else el.setAttribute('selected', '');

        // hack to correct buggy behavior
        var select = el.parentNode.cloneNode(true);
        el.parentNode.parentNode.replaceChild(select, el.parentNode);
    
<h4>From</h4>

<div>
    <select name="sites-list" size="7" multiple>
        <option value="site-1">SITE</option>
        <option value="site-2" selected>SITE</option>
        <option value="site-3">SITE</option>
        <option value="site-4">SITE</option>
        <option value="site-5">SITE</option>
        <option value="site-6" selected>SITE</option>
        <option value="site-7">SITE</option>
        <option value="site-8">SITE</option>
        <option value="site-9">SITE</option>
    </select>
</div>

【讨论】:

这对我有用,但选择不会使表单变脏 (e.preventDefault())。只是要记住的事情。 请解释您所说的“错误行为”是什么意思 e.preventDefault() 是做什么的?【参考方案3】:

techfoobar的回答有问题,如果你拖动鼠标,它会取消选择所有选项。

Sergio 的回答很有趣,但是克隆和删除绑定到下拉列表的事件并不是一件好事。

Try this answer.

注意:不适用于 Firefox,但可以在 Safari/Chrome/Opera 上完美运行。 (我没在IE上测试过)

编辑(2020 年)

在我最初回答 5 年后,我认为这里的最佳做法是用复选框替换下拉菜单。想想看,这就是复选框首先存在的主要原因,它可以很好地与 IE 和现代手机等旧浏览器配合使用,无需任何自定义 JS 来处理所有古怪的场景。

【讨论】:

这个确实是最好的,点击时不会向上滚动。【参考方案4】:

死灵术。 没有 jQuery 的选定答案。 此外,单击选项时它错过了设置焦点,因为您必须自己执行此操作,如果您编写 e.preventDefault... 忘记做焦点会影响 CSS 样式,例如引导等。

var options = [].slice.call(document.querySelectorAll("option"));

options.forEach(function (element)

    // console.log("element", element);
    element.addEventListener("mousedown", 
        function (e)
        
            e.preventDefault();
            element.parentElement.focus();
            this.selected = !this.selected;
            return false;
        
        , false
    );
);

【讨论】:

它仍然跳到第一个选项我做错了什么?【参考方案5】:

我今天遇到了同样的问题,一般建议是使用隐藏复选框列表并通过 css 模拟行为,这样更容易管理,但在我的情况下,我不想修改 html

目前我只用谷歌浏览器测试了这段代码,我不知道是否适用于其他浏览器,但它应该:

var changed;
$('select[multiple="multiple"]').change(function(e) 
    var select = $(this);
    var list = select.data('prevstate');
    var val = select.val();
    if (list == null) 
        list = val;
     else if (val.length == 1) 
        val = val.pop();
        var pos = list.indexOf(val);
        if (pos == -1)
            list.push(val);
        else
            list.splice(pos, 1);
     else 
        list = val;
    
    select.val(list);
    select.data('prevstate', list);
    changed = true;
).find('option').click(function() 
    if (!changed)
        $(this).parent().change();
    
    changed = false;
);

当然欢迎提出建议,但我还没有找到其他方法

【讨论】:

以上是关于如何避免使用 Javascript 在多选框中进行 ctrl-click 的需要?的主要内容,如果未能解决你的问题,请参考以下文章

如何禁用多选框中的其余所有项目

多选框其他,css基础,选择器基础

防止多选框在移动浏览器上的多选框中不更改

如何实现 JS实现select多选框 全选

vue添加第一行为空的多选框

CRM手记- 11 | Django