如何避免使用Javascript在多选框中按住ctrl键单击的需要?


70

我以为这将是一个简单的技巧,但是我已经搜索了几个小时,找不到合适的搜索词。我希望有一个普通的多重选择框(<select multiple="multiple">),但我不想用户必须按住控制键才能进行多重选择。

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

有人可以建议用Javascript做到这一点的简单方法吗?谢谢。


如果您不介意更改标记,则可以构建复选框和标签的列表,然后隐藏复选框,并设置标签的样式(在选中输入时),使其外观与相似<select multiple>小提琴中的演示
KyleMit

Answers:


111

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

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

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

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


2
您可以! this.selected在那里使用。
Alex

1
这取决于jQuery。确保在加载DOM元素并准备绑定到事件后执行上述代码。放置它的好地方是在您的$(document).ready(...)
techfoobar

1
不能正常工作。拖动鼠标后,它将取消选择所有选项。
evilReiko 2015年

2
很好的解决方案。我注意到的唯一缺点是,事件预防的工作方式是父选择不被关注,从而产生了不同的外观和感觉(灰色而不是所选选项的蓝色背景)。为了保留外观,我手动将焦点放在选择框上。$(this.parentElement).focus();
Uluaiv

1
正如其他所有人所说,为简化起见,this.selected = !this.selected;确实不需要使用jQuery
doz87

20

我本人要解决此问题,并注意到错误的行为是对mousedown和属性的简单拦截,因此可以覆盖select元素,并且效果很好。

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

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

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>


1
这对我有用,但是选择不会使表格变脏(e.preventDefault())。只是要记住一点。
HanletEscaño16年

请解释“越野车行为”的意思
Kelly Elton

怎么e.preventDefault()办?
Marvin

6

techfoobar的答案是越野车,如果拖动鼠标,它将取消选择所有选项。

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

试试这个答案

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

编辑(2020)

在我最初回答5年后,我认为此处的最佳做法是将复选框替换为下拉菜单。考虑一下,这就是为什么复选框首先存在的主要原因,并且它可以与IE和现代移动设备(如没有任何自定义JS)来处理所有古怪场景的旧浏览器很好地配合使用。


实际上,这是最好的一个,单击时不会向上滚动。
rafael.js 2016年

3

死灵法师。
所选答案不带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
    );
});

1
它仍然跳到第一个选项,我做错了什么?
卢西亚诺·安德列斯·马蒂尼(Laiano Martini),

1

我今天遇到了同样的问题,通常的建议是使用隐藏的复选框列表,并通过CSS模拟行为,这样更易​​于管理,但就我而言,我不想修改html。

目前,我仅使用google chrome测试了此代码,但不知道是否可以在其他浏览器上使用,但应该:

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

当然可以提出建议,但我没有找到其他方法

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.