jQuery Sortable and Droppable

前端 未结 6 2033
抹茶落季
抹茶落季 2020-12-04 22:28

I want to have a list that is sortable, but I also want the elements in that list to be droppable to the divs I have defined as droppable. I can\'t seem to find a way to do

相关标签:
6条回答
  • 2020-12-04 22:31

    As far as I could tell, the issue with the previous code I posted is that the drop function of the droppable was getting called before the mouseup of the sortable, and since I rewrote the list the sortable was getting angry (for lack of better terms). That's somewhat a guess.

    Looking at the final code:

    <html>
    <head>
        <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.js"></script>
        <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.js"></script>
        <script type="text/javascript">
    
    var dropped = false;
    var templateHtml;
    $(document).ready(function(){
    
        setSortable();
    
        $("#droppable").droppable({
            activeClass: 'active',
            hoverClass:'hovered',
            accept:".drop",
            drop:function(event,ui){
                dropped = true;
                //alert(ui.draggable.text());
            }
        });
    
    });
    
    function setSortable(){
        $("#sortable").sortable({
            stop:function(event,ui){
                if(dropped){
                    $("#sortable").sortable('destroy').html(templateHtml);
                    dropped = false;
                    setSortable();
                }
            }
        });
    
        $("#sortable li").addClass("drop").bind('mousedown',function(){
            templateHtml = $("#sortable").html();
        });
    }
    
        </script>
        <style type="text/css">
        #sortable li{
            clear:both;
            float:left;
        }
    
        #droppable {
            clear:both;
            height:300px;
            width:400px;
            background-color:#CCC;
        }
        #droppable.active {
            background-color:#CFC;
        }
        #droppable.hovered {
            background-color:#CCF;
        }
        </style>
    
    </head>
    <body>
    
    <ul id="sortable">
    <li id="one">One</li>
    <li id="two">Two</li>
    <li id="three">Three</li>
    <li id="four">Four</li>
    <li id="five">Five</li>
    <li id="six">Six</li>
    </ul>
    
    <div id="droppable">
    Drop Here
    </div>
    
    </body>
    

    Tons of quirks are involved here.

    I tried to save the #sortable html on the start event of sortable, but that get's called after all of the ui-css gets applied, and ended up placing list elements in crazy places. So, I needed to use the mousedown function on the LIs.

    The setSortable is in a function because the stop event rewrites the sortable, which is "recursive" I guess. Not sure the exact terminology here, but we can go with annoyingly confusing.

    Fortunately, the droppable's drop function gets called before the sortables stop function, so I was able to set a global "dropped" variable that was used to see if the element was dropped.

    I'm still surprised this wasn't easier to do, I thought jQuery would have functions to handle it a lot better. Perhaps I'm missing something?

    0 讨论(0)
  • 2020-12-04 22:38

    Not exactly what you asked for, but I needed an initial container where the items could be dragged to another sortable container - and thought I should share it. This was how I achieved it (jQuery 1.8.3):

    $("#sortable-list").sortable();
    $("#initial-list div").draggable({
      revert: true,
      revertDuration: 0
    });
    
    $("#initial-list").droppable({
      accept: ".item-selected",
      drop: function(e, ui) {
        var dropped = ui.draggable;
        var droppedOn = $(this);
        var itemInOtherList = $(this).children("#" + dropped.attr('id'));
        itemInOtherList.removeClass('ui-state-disabled').draggable({ disabled: false });
        dropped.remove();
      }
    });
    $("#sortable-list").droppable({
      accept: ".item-initial",
      drop: function(e, ui) {
        var dropped = ui.draggable;
        var droppedOn = $(this);
        droppedOn.append(dropped.clone()
          .removeAttr('style')
          .removeClass("item-initial")
          .addClass("item-selected"));
        dropped.animate(dropped.data().origPosition, {
          complete: function() {
            $(this).addClass('ui-state-disabled').draggable({ disabled: true });
          }
        });
      }
    });
    

    JSFiddle: http://jsfiddle.net/Muskar/dwz4mvxa/8/

    0 讨论(0)
  • 2020-12-04 22:39

    I've spent all day on this, and I've gotten a lot closer, but still not doing as well as I'd like. I now have the functionality I need, but a Javascript error is getting thrown.

    The issue is getting the sortable list to return to its previous position if the element is dropped in the droppable, rather than in the list. Currently, I'm saving the html onmousedown, then rewriting the html in the drop function of the droppable. This works, but its giving me a jquery variable is null error. Can anyone find a better solution?

    Code:

    <html>
    <head>
        <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.js"></script>
        <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.js"></script>
        <script type="text/javascript">
    
    var templateHtml;
    $(document).ready(function(){
    
        $("#sortable").sortable();
        $("#sortable li").addClass("drop").bind('mousedown',function(){
            templateHtml = $("#sortable").html();
        });
        $("#droppable").droppable({
            activeClass: 'active',
            hoverClass:'hovered',
            accept:".drop",
            drop:function(event,ui){
                $("#sortable").sortable('destroy').html(templateHtml);
                $("#sortable").sortable();
                $("#sortable li").addClass("drop").bind('mousedown',function(){
                    templateHtml = $("#sortable").html();
                });          
            }
        });
    
    });
    
        </script>
        <style type="text/css">
        #sortable li{
            clear:both;
            float:left;
        }
    
        #droppable {
            clear:both;
            height:300px;
            width:400px;
            background-color:#CCC;
        }
        #droppable.active {
            background-color:#CFC;
        }
        #droppable.hovered {
            background-color:#CCF;
        }
        </style>
    
    </head>
    <body>
    
    <ul id="sortable">
    <li id="one">One</li>
    <li id="two">Two</li>
    <li id="three">Three</li>
    <li id="four">Four</li>
    <li id="five">Five</li>
    <li id="six">Six</li>
    </ul>
    
    <div id="droppable">
    Drop Here
    </div>
    
    </body>
    
    0 讨论(0)
  • 2020-12-04 22:53

    Was able to get a similar end result by making the each of the target DIVs their own sortables.

    I then, via connectWith, made all of the sortables able to connect and share draggables.

    Something like:

    var connects = '#main_sortable, div.target';
    $('#main_sortable').sortable({ connectWith: connect });
    $('div').sortable({ connectWith: connect} );
    
    0 讨论(0)
  • 2020-12-04 22:53

    If you can allow your other droppable areas to be sortable as well, you can use the connectWith option with a common selector:

    <div id="droppable1" class="droppable-area"></div>
    <div id="droppable2" class="droppable-area"></div>
    <div id="droppable3" class="droppable-area"></div>
    

    your jQuery code would then be:

    $('.droppable-area').sortable({ connectWith: '.droppable-area' });
    

    This solution worked beautifully for me anyways.

    0 讨论(0)
  • 2020-12-04 22:56

    Here's a simplified version of Colin's solution.

    The biggest difference is that this solution does not store the entire html of the sortable elements, but only the currently dragged item. It is then inserted into it's original position if the item is dropped on the droppable area.

    Anyway, here's the code:

    <!doctype html>
    <html>
    <head>
        <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js"></script>
        <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.5/jquery-ui.js"></script>
    
    <script type="text/javascript">
    $(document).ready(function() {
        var dropped = false;
        var draggable_sibling;
    
        $("#sortable").sortable({
            start: function(event, ui) {
                draggable_sibling = $(ui.item).prev();
            },
            stop: function(event, ui) {
                if (dropped) {
                    if (draggable_sibling.length == 0)
                        $('#sortable').prepend(ui.item);
    
                    draggable_sibling.after(ui.item);
                    dropped = false;
                }
            }
        });
    
        $(".droppable").droppable({
            activeClass: 'active',
            hoverClass:'hovered',
            drop:function(event,ui){
                dropped = true;
                $(event.target).addClass('dropped');
            }
        });
    });
    
    </script>
    
    <style type="text/css">
    #sortable li{
        clear:both;
        float:left;
    }
    
    .droppable {
        clear:both;
        height:300px;
        width:400px;
        background-color:#CCC;
    }
    
    .droppable.active { background: #CFC; }
    .droppable.hovered { background: #CCF; }
    .dropped { background: #f52; }
    </style>
    
    </head>
    <body>
    
    <ul id="sortable">
        <li id="one">One</li>
        <li id="two">Two</li>
        <li id="three">Three</li>
        <li id="four">Four</li>
        <li id="five">Five</li>
        <li id="six">Six</li>
    </ul>
    
    <div class="droppable">Drop Here</div>
    <div class="droppable">Drop Here</div>
    
    </body>
    </html>
    

    It still suffers the same problem as Colin's solution if an item is dragged into a new position in the list and then dropped outside both the <ul> and the droppable <div>. The item will then not reset but take the last position in the list (tested in Google Chrome). Anyway, this is easily solved with some mouse over detection or it may even be desirable behaviour.

    0 讨论(0)
提交回复
热议问题