使用 jQuery UI 使可拖动元素在可放置中可排序

Posted

技术标签:

【中文标题】使用 jQuery UI 使可拖动元素在可放置中可排序【英文标题】:Make draggable element sortable within droppable using jQuery UI 【发布时间】:2014-01-25 23:50:09 【问题描述】:

已解决

所以我对sortable()connectWith 属性进行了更多研究,发现解决方案比我预期的要简单,但由于draggable()droppable(),我在考虑它有点倒退。

这是小提琴:http://jsfiddle.net/DKBU9/12/


原问题如下:

这是我认为应该分开的先前 SO 问题的扩展。

原来的问题在这里:jQuery UI - Clone droppable/sortable list after drop event。它涉及在克隆元素上重新初始化 droppable 处理程序。

不过,最重要的是,我正在尝试允许从初始列表中拖动的元素在可放置列表中进行排序。

这是一个小提琴,基本上说明了原始问题导致的当前行为:http://jsfiddle.net/DKBU9/7/

以及所需的代码,因为 SO 喜欢抱怨和膨胀这些帖子:

html

<ul id="draggables">

    <li>foo1</li>
    <li>foo2</li>
    <li>foo3</li>

</ul>

<ul class="droppable new">

</ul>

JS

$(function() 

    $('#draggables > li').draggable(
        appendTo: 'document',
        revert: 'invalid'
    );

    $('.droppable > li').draggable(
        appendTo: 'document',
        revert: 'invalid'
    );

    $('#draggables').droppable(
        accept: '.droppable > li',
        drop: function(event, ui) 
            ui.draggable.detach().css(top: 0,left: 0).appendTo($(this));
            cleanUp();
        
    );

    initDrop($('.droppable'));

);

function initDrop($element) 

    $element.droppable(
        accept: function(event, ui) 
            return true;
        ,
        drop: function(event, ui) 
            if($(this).hasClass('new')) 
                var clone = $(this).clone();                
                $(this).after(clone);
                $(this).removeClass('new');
                initDrop( clone );
            
            ui.draggable.detach().css(top: 0,left: 0).appendTo($(this));  
            cleanUp();
        
    ).sortable(
        items: 'li',
        revert: false,
        update: function() 
            cleanUp();   
        
    );



function cleanUp() 

    $('.droppable').not('.new').each(function() 
        if($(this).find('li').length == 0) 
            $(this).remove();
        
    );


参考问题:Jquery UI combine sortable and draggable

我一直在尝试使用这个 SO question 来解决我的问题,因为结果正是我想要实现的,特别是接受答案的 cmets 中提供的最后一个小提琴,但我似乎无法考虑到细微的差异,弄清楚如何使其适应我的代码。例如,该问题中的小提琴克隆了可拖动元素而不是拖动实际元素,并且与我的不同,它不允许将元素拖回初始列表中。

因此,对于尝试为我的代码获得该结果的任何帮助将不胜感激。

此外,在该示例中,accept 属性设置为返回 true 的函数。这是什么原因?这不只是意味着它会接受任何东西,或任何可拖动的元素吗?

编辑:我读了几个答案,它们只是将 sortable() 与 connectWith 属性一起使用,但由于某种原因,我认为它没有达到我需要的效果,部分原因是我不希望初始列表是可排序的也是。然而,单独使用 sortable() 似乎可以获得我所追求的功能,但我还没有适应所有的事件处理程序。

【问题讨论】:

我的回答将允许初始列表不能根据您的编辑进行排序,但如果您可以接受它是可排序的,那么我认为您应该使用您的,因为它更简单。 是的,非常感谢您的时间和精力,但我会坚持这一点,因为初始列表是可排序的并不是什么大问题。 【参考方案1】:

this fiddle

它将使项目在新列表中可放置和排序,但不是在初始列表中(根据您的编辑)。

有几个技巧:

1) 从可拖动元素开始,我添加了一个新函数,因为我们需要保留一个占位符(使用克隆),以便容器在拖动过程中不会跳跃,我们需要将新元素初始化为可拖动元素。

function initDraggable($element)

    $($element).draggable(
        connectToSortable: '.droppable',     
        revert: function(droppableObj)
        
            if(droppableObj === false)
                             
                $(this).removeClass('dragging');
                return true;
             
             else
                           
                return false;
             
        ,
        helper: 'clone',
        start: function(e, ui)
                   
            $draggingParent = $(this).parent();
           $(this).addClass('dragging');
        
    );

注意 connectToSortable:.droppable (作为清理,我认为您应该将 droppable 更改为 sortable);

还要注意revert: - 这让我们有机会在还原时删除“拖动”类(这会使原始(克隆)元素不可见)。

最后,start 添加了“拖动”类,使原始(克隆)元素在拖动过程中不可见。它还设置了 $draggingParent 用于检查是否从#draggables.droppables 拖动项目。

2) 然后是droppable() 对应#draggables

 $("#draggables").droppable(    
    drop: function(ev, ui) 
        if($draggingParent[0] === $(ui.helper).parent()[0])
        
            //dragged from draggables to draggables
            $(ui.draggable).removeClass('dragging');
        
        else
                    
            if(ui.draggable.parent())
            var $clone = $(ui.draggable).clone();
            $(ui.draggable).remove();
            $clone.removeClass();
            $clone.removeAttr('style');
            initDraggable($clone);
            $(this).append($clone);        
        
    

请注意,drop 处理程序会检查此元素是否从 #draggables.droppables 中删除并采取相应措施。

3) 最后,正如你已经提到的,我们真的希望 droppable 是可排序的:

function initDroppableSort($element)        
    $element.sortable(
       items: 'li',
        connectWith: ".droppable,#draggables",
        revert: true,
       stop: function(event, ui) 
           $(ui.item).removeClass('dragging');
            $('.dragging').remove();
            if($(this).hasClass('new')) 
                var clone = $(this).clone();                
                clone.empty();
                $(this).after(clone);
                $(this).removeClass('new');
                initDroppableSort( clone );
                        
            cleanUp();
        
    );


注意connectWith,特别是它指的是.droppable#draggables

【讨论】:

以上是关于使用 jQuery UI 使可拖动元素在可放置中可排序的主要内容,如果未能解决你的问题,请参考以下文章

jQuery UI:使用容差触摸放置对象时的可拖动行为

在可拖动的 JQuery UI 上手动触发“堆栈”选项

如何使用 jQuery 将可拖动项目居中放置在可放置的图像地图区域上?

如何使可拖动元素在拖放时保持在新位置(HTML5 不是 jQuery)?

jQuery 可拖动和可拖放,在可拖动 ul 上滚动

jquery 可拖动 + 可在放置事件时使用自定义 html 排序?