jQuery Sortable - 选择并拖动多个列表项

时间:2010-09-23 01:16:11

标签: jquery jquery-ui

我有一个设计,我有一个“可用框”列表,用户通过将它们从“可用框”列表拖到他们的“我的框”列表来获取框。

用户通常一次多取几个盒子(最多20个),一旦他们完成了盒子,他们就会将它们拖回“可用的盒子”列表以返回它们。

jQuery sortable允许我一次拖动一个框,从用户的角度来看是不合需要的。我一直无法找到解决问题的简单方法。

我可能必须完全提出不同的UI方法,但首先是否有人对如何实现这一点有任何建议?

谢谢!

5 个答案:

答案 0 :(得分:74)

工作解决方案

tl; dr Refer to this Fiddle for a working answer


我到处寻找解决将多个选定项目从可排序项拖动到连接的可排序的问题,这些答案是我能找到的最佳答案。

然而...

接受的答案是错误的, @Shanimal's answer已接近,但不完整。我拿了@Shanimal的代码并建立在它上面。

我修好了:

我补充说:

  • 正确 Ctrl +单击(或 Cmd +单击,如果在Mac上)支持选择多个项目。单击按住 Ctrl 键将导致选择该项目,并且取消选择同一列表中的其他项目。这与jQuery UI Selectable() widget的点击行为相同,不同之处在于Selectable()在mousedrag上有一个选框。

Fiddle

<强> HTML:

<ul>
    <li>One</li>
    <li>Two</li>
    <li>Three</li>
</ul>
<ul>
    <li>Four</li>
    <li>Five</li>
    <li>Six</li>
</ul>

JavaScript(使用jQuery和jQuery UI):

$("ul").on('click', 'li', function (e) {
    if (e.ctrlKey || e.metaKey) {
        $(this).toggleClass("selected");
    } else {
        $(this).addClass("selected").siblings().removeClass('selected');
    }
}).sortable({
    connectWith: "ul",
    delay: 150, //Needed to prevent accidental drag when trying to select
    revert: 0,
    helper: function (e, item) {
        var helper = $('<li/>');
        if (!item.hasClass('selected')) {
            item.addClass('selected').siblings().removeClass('selected');
        }
        var elements = item.parent().children('.selected').clone();
        item.data('multidrag', elements).siblings('.selected').remove();
        return helper.append(elements);
    },
    stop: function (e, info) {
        info.item.after(info.item.data('multidrag')).remove();
    }

});

注意:

自从我发布这个以来,我实现了一些类似的东西 - 将可拖动的列表项连接到具有多选功能的可排序项。它的设置几乎完全相同,因为jQuery UI小部件非常相似。一个UI提示是确保为draggables或selectables设置了delay参数,因此您可以单击以选择多个项目而不启动拖动。然后你构建一个帮助看起来就像所有选中的元素放在一起(制作一个新元素,克隆选定的项目,然后追加它们),但确保离开原始项目完好无损(否则它搞砸了功能 - 我不能确切地说为什么,但它涉及很多令人沮丧的DOM异常)。

我还添加了 Shift + Click 功能,使其功能更像本机桌面应用程序。我可能要开始一个博客,所以我可以更详细地阐述这个: - )

答案 1 :(得分:47)

我没有使用sortable工作,但我确实使用了draggable&amp;可弃。我不知道我是否涵盖了你需要的所有功能,但它应该是一个好的开始(demo here):

HTML

<div class="demo">
    <p>Available Boxes (click to select multiple boxes)</p>    
    <ul id="draggable">
        <li>Box #1</li>
        <li>Box #2</li>
        <li>Box #3</li>
        <li>Box #4</li>
    </ul>

    <p>My Boxes</p>
    <ul id="droppable">
    </ul>

</div>

脚本

$(document).ready(function(){

    var selectedClass = 'ui-state-highlight',
        clickDelay = 600,     // click time (milliseconds)
        lastClick, diffClick; // timestamps

    $("#draggable li")
        // Script to deferentiate a click from a mousedown for drag event
        .bind('mousedown mouseup', function(e){
            if (e.type=="mousedown") {
                lastClick = e.timeStamp; // get mousedown time
            } else {
                diffClick = e.timeStamp - lastClick;
                if ( diffClick < clickDelay ) {
                    // add selected class to group draggable objects
                    $(this).toggleClass(selectedClass);
                }
            }
        })
        .draggable({
            revertDuration: 10, // grouped items animate separately, so leave this number low
            containment: '.demo',
            start: function(e, ui) {
                ui.helper.addClass(selectedClass);
            },
            stop: function(e, ui) {
                // reset group positions
                $('.' + selectedClass).css({ top:0, left:0 });
            },
            drag: function(e, ui) {
                // set selected group position to main dragged object
                // this works because the position is relative to the starting position
                $('.' + selectedClass).css({
                    top : ui.position.top,
                    left: ui.position.left
                });
            }
        });

    $("#droppable, #draggable")
        .sortable()
        .droppable({
            drop: function(e, ui) {
                $('.' + selectedClass)
                 .appendTo($(this))
                 .add(ui.draggable) // ui.draggable is appended by the script, so add it after
                 .removeClass(selectedClass)
                 .css({ top:0, left:0 });
            }
        });

});

答案 2 :(得分:20)

JSFiddle:http://jsfiddle.net/hQnWG/

<style>
    ul {border:1px solid Black;width:200px;height:200px;display:inline-block;vertical-align:top}
    li {background-color:Azure;border-bottom:1px dotted Gray}   
    li.selected {background-color:GoldenRod}
</style>
<h1>Click items to select them</h1>
<ul>
    <li>One</li>
    <li>Two<li>
    <li>Three</li>
</ul><ul>
    <li>Four</li>
    <li>Five<li>
    <li>Six</li>
</ul>
<script>
    $("li").click(function(){
        $(this).toggleClass("selected");
    })
    $("ul").sortable({
        connectWith: "ul",
        start:function(e,info){
            // info.item.siblings(".selected").appendTo(info.item);
            info.item.siblings(".selected").not(".ui-sortable-placeholder").appendTo(info.item);

        },
        stop:function(e,info){
            info.item.after(info.item.find("li"))
        }
    })
</script>

答案 3 :(得分:6)

有一个jQuery UI插件:https://github.com/shvetsgroup/jquery.multisortable

jsFiddle:http://jsfiddle.net/neochief/KWeMM/

$('ul.sortable').multisortable();

答案 4 :(得分:1)

Aaron Blenkush的解决方案有一个主要错误:删除和添加可排序列表中断结构的项目;刷新可以提供帮助,但是如果其他功能处理列表,则需要刷新所有这些功能,这一切都变得过于复杂。

在stackoverflow上分析了一些解决方案后,我总结了以下内容:

不要使用帮助器 - 使用启动功能,因为它已经有ui.item,默认是帮助器。

    start: function(event, ui){
        // only essential functionality below

        // get your own dragged items, which do not include ui.item;
        // the example shows my custom select which selects the elements
        // with ".selected" class
        var dragged = ui.item.siblings(arr["nested_item"]).children('.tRow.tSelected').parent(arr["nested_item"]);

        // clone the dragged items
        var dragged_cloned = dragged.clone();

        // add special class for easier pick-up at update part
        dragged_cloned.each(function(){$(this).addClass('drag_clone');});

        // record dragged items as data to the ui.item
        ui.item.data('dragged', dragged);

        // hide dragged from the main list
        dragged.hide();

        // attached cloned items to the ui.item - which is also ui.helper
        dragged_cloned.appendTo(ui.item);
        },
  1. 在更新部分:

    update: function(event, ui){
        // only essential functionality below
    
        // attach dragged items after the ui.item and show them
        ui.item.after(ui.item.data("dragged").show());
    
        // remove cloned items
        ui.item.children(".drag_clone").remove();
        },
    
  2. 停止功能可能需要更新功能的一些副本,但可能与更新分开,因为如果没有更改 - 不要向服务器提交任何内容。

    添加:保留拖动项目的顺序。