带有动画的 jQuery 可排序

Posted

技术标签:

【中文标题】带有动画的 jQuery 可排序【英文标题】:jQuery Sortable with animation 【发布时间】:2011-06-30 22:17:09 【问题描述】:

我正在使用 jQuery 和 Sortable 来排列我的项目列表(还有这个 http://dragsort.codeplex.com)。

一切都很完美。

我正在使用dragEnd 上的函数来按顺序排列列表。

这是我的代码:

$("#list1, #list2").dragsort( dragSelector: "div",
                               dragBetween: true,
                               dragEnd: saveOrder,
                               placeHolderTemplate: "<li class='placeHolder'><div></div></li>" );

function saveOrder() 
    var data = $("#list1 li").map(function()  return $(this).children().html(); ).get();
    $("input[name=list1SortOrder]").val(data.join("|"));
;

我的问题:我是否可以在拖动时制作动画?或者在拖动时重新定位元素?我只需要它在 Safari 上工作。

一个例子是这样的:

http://www.youtube.com/watch?v=U3j7mM_JBNw

看看拖放(0:30),你会明白我在说什么。

谢谢。

【问题讨论】:

你的 CSS 是什么样的?这实际上应该是真实的行为.. 我的 CSS 非常简单。只使用浮动宽度和高度。 你或许可以通过适配 QuickSand 找到解决方案 - razorjack.net/quicksand 我已提出相关功能请求here 【参考方案1】:

聚会有点晚了,但我决定使用 jQuery 找到解决方案,因为在这个主题上几乎没有帮助,尤其是复制 Facebook 等网络应用程序中存在的功能及其相册的图像拖放重新排序,以及随之而来的漂亮动画......

所以我想出了一个似乎非常有效的解决方案,我会尽我所能解释它!来了……

这里最大的问题是不仅要为可排序对象设置动画,还要弄清楚它们需要动画到哪里——当涉及到像画廊中的图像这样的浮动元素时,这真是太棒了!为了解决这个问题,我决定.clone() 原始浮动LI 项目,使用小于原始@ 的z-index 值将克隆绝对定位在原始LI 项目之下 987654327@ 项目,然后当从 jQuery 可排序的 change 事件触发时,我可以检测到原始 LI 的位置并将绝对定位的克隆动画到这些位置。剩下的就是简单地适当地显示/隐藏元素以获得所需的效果。

这是代码,从 HTML 开始:

<ul id="original_items">
    <li><img src="something.jpg" /></li>
    <li><img src="something.jpg" /></li>
    <li><img src="something.jpg" /></li>
</ul>

<ul id="cloned_items">
</ul>

所以我们有我们要排序的原始项目,以及克隆项目的容器。 CSS 的时间:

#original_items, #cloned_items 
    list-style: none;


#original_items li 
    float: left;
    position: relative;
    z-index: 5;


#cloned_items li 
    position: absolute;
    z-index: 1;

使用我们的 CSS,我们只是删除任何列表样式、浮动我们的原始元素并设置 z-index 要求以确保克隆的项目位于原始项目的下方。请注意原始项目上的 relative 位置,以确保它们的行为符合预期。为什么在下面问?它会(希望)通过一些 javascript 变得清晰:

jQuery(function()

    // loop through the original items...
    jQuery("#original_items li").each(function()

        // clone the original items to make their
        // absolute-positioned counterparts...
        var item = jQuery(this);
        var item_clone = item.clone();
        // 'store' the clone for later use...
        item.data("clone", item_clone);

        // set the initial position of the clone
        var position = item.position();
        item_clone.css("left", position.left);
        item_clone.css("top", position.top);

        // append the clone...
        jQuery("#cloned_items").append(item_clone);
    );

    // create our sortable as usual...
    // with some event handler extras...
    jQuery("#original_items").sortable(

        // on sorting start, hide the original items...
        // only adjust the visibility, we still need
        // their float positions..!
        start: function(e, ui)
            // loop through the items, except the one we're
            // currently dragging, and hide it...
            ui.helper.addClass("exclude-me");
            jQuery("#original_items li:not(.exclude-me)")
                .css("visibility", "hidden");

            // get the clone that's under it and hide it...
            ui.helper.data("clone").hide();
        ,

        stop: function(e, ui)
            // get the item we were just dragging, and
            // its clone, and adjust accordingly...
            jQuery("#original_items li.exclude-me").each(function()
                var item = jQuery(this);
                var clone = item.data("clone");
                var position = item.position();

                // move the clone under the item we've just dropped...
                clone.css("left", position.left);
                clone.css("top", position.top);
                clone.show();

                // remove unnecessary class...
                item.removeClass("exclude-me");
            );

            // make sure all our original items are visible again...
            jQuery("#original_items li").css("visibility", "visible");
        ,

        // here's where the magic happens...
        change: function(e, ui)
            // get all invisible items that are also not placeholders
            // and process them when ordering changes...
            jQuery("#original_items li:not(.exclude-me, .ui-sortable-placeholder)").each(function()
                var item = jQuery(this);
                var clone = item.data("clone");

                // stop current clone animations...
                clone.stop(true, false);

                // get the invisible item, which has snapped to a new
                // location, get its position, and animate the visible
                // clone to it...
                var position = item.position();
                clone.animate(
                    left: position.left,
                    top:position.top, 500);
            );
        
    );
);

哇,我真的希望这是有道理的,并且可以帮助某人制作可排序列表的动画,但对于任何感兴趣的人来说,这都是一个可行的示例! :)

【讨论】:

@Daniel - 感谢您的反馈,我希望它有意义! 感谢这段代码,它运行良好。只是想知道您是否知道为什么在 li 上使用 % 宽度然后调整浏览器大小时会中断? @Parallel2ne - 如果不看一些代码,或者不知道到底是什么问题,很难说,但如果我不得不猜测,我会说它是你所指的克隆项目作为“破碎”?这可能是由于克隆项目的样式,因为它们是绝对放置的,并且需要它们的容器 (ul#cloned_items) 的样式与原始项目的容器 (ul#original_items) 的样式相同,以正确接受适当的宽度% 的。如果克隆项目的容器不是 100% 宽,那么克隆项目的宽度就没有任何基础。有道理? :') 我确实明白你在说什么 :) 在你执行另一个可排序的操作 jsfiddle.net/jamestoone/dNfsJ/48 后它会自行修复@任何帮助将不胜感激 @Parallel2ne - 这可能是一个愚蠢的问题,但你为什么将li 元素的中间线(金色)浮动到右侧而不是左侧?我删除了 CSS (updated jsFiddle here) 的第 19 行,响应似乎更好。我不确定这是否能解决您最初的担忧?【参考方案2】:

刚刚实现了 Chris Kempen 所说的话: http://jsfiddle.net/dNfsJ/

jQuery(function()

// loop through the original items...
jQuery("#original_items li").each(function()

    // clone the original items to make their
    // absolute-positioned counterparts...
    var item = jQuery(this);
    var item_clone = item.clone();
    // 'store' the clone for later use...
    item.data("clone", item_clone);

    // set the initial position of the clone
    var position = item.position();
    item_clone.css("left", position.left);
    item_clone.css("top", position.top);

    // append the clone...
    jQuery("#cloned_items").append(item_clone);
);

// create our sortable as usual...
// with some event handler extras...
jQuery("#original_items").sortable(

    // on sorting start, hide the original items...
    // only adjust the visibility, we still need
    // their float positions..!
    start: function(e, ui)
        // loop through the items, except the one we're
        // currently dragging, and hide it...
        ui.helper.addClass("exclude-me");
        jQuery("#original_items li:not(.exclude-me)")
            .css("visibility", "hidden");

        // get the clone that's under it and hide it...
        ui.helper.data("clone").hide();
    ,

    stop: function(e, ui)
        // get the item we were just dragging, and
        // its clone, and adjust accordingly...
        jQuery("#original_items li.exclude-me").each(function()
            var item = jQuery(this);
            var clone = item.data("clone");
            var position = item.position();

            // move the clone under the item we've just dropped...
            clone.css("left", position.left);
            clone.css("top", position.top);
            clone.show();

            // remove unnecessary class...
            item.removeClass("exclude-me");
        );

        // make sure all our original items are visible again...
        jQuery("#original_items li").css("visibility", "visible");
    ,

    // here's where the magic happens...
    change: function(e, ui)
        // get all invisible items that are also not placeholders
        // and process them when ordering changes...
        jQuery("#original_items li:not(.exclude-me, .ui-sortable-placeholder)").each(function()
            var item = jQuery(this);
            var clone = item.data("clone");

            // stop current clone animations...
            clone.stop(true, false);

            // get the invisible item, which has snapped to a new
            // location, get its position, and animate the visible
            // clone to it...
            var position = item.position();
            clone.animate(
                left: position.left,
                top:position.top, 500);
        );
    
);

【讨论】:

【参考方案3】:

虽然此解决方案非常适合创建初始过渡,但当项目回弹时,没有过渡。解决方案比我预期的要容易。您需要做的就是调整 .sortable() 中的 revert 选项

像这样:

     <script>
      $(document).ready(function() 
        $( "#sortable" ).sortable(
         tolerance: 'pointer',
         revert: 'invalid'
        ).disableSelection();
      );
     </script>

jQuery UI API:http://api.jqueryui.com/sortable/#option-revert

这样可以顺利过渡到物品的新家。

Click here for EXAMPLE on jsFiddle

【讨论】:

不幸的是,当您“取消”排序或删除事件时,“还原”选项不适用。被取消的项目会立即恢复,而不是平滑地动画。【参考方案4】:

你为什么不在 jqueryui 上使用 Sortable? http://jsfiddle.net/KgNCD/

JS:

$( "#sortable" ).sortable(       
    start: function(e, ui)
        $(ui.placeholder).hide(300);
    ,
    change: function (e,ui)
        $(ui.placeholder).hide().show(300);
    
);                           
$("#sortable").disableSelection();

HTML:

<ul id="sortable">
    <li class="ui-state-default">1</li>
    <li class="ui-state-default">2</li>
    <li class="ui-state-default">3</li>
    <li class="ui-state-default">4</li>
    <li class="ui-state-default">5</li>
    <li class="ui-state-default">6</li>
    <li class="ui-state-default">7</li>
    <li class="ui-state-default">8</li>
    <li class="ui-state-default">9</li>
    <li class="ui-state-default">10</li>
    <li class="ui-state-default">11</li>
    <li class="ui-state-default">12</li>
</ul>

【讨论】:

是的,我想,但我怎样才能在下降之前为元素设置动画?【参考方案5】:

来自上面的 jsfiddle 答案(http://jsfiddle.net/KgNCD/2/):

$( "#sortable" ).sortable(       
    start: function(e, ui)
        $(ui.placeholder).hide(300);
    ,
    change: function (e,ui)
        $(ui.placeholder).hide().show(300);
    
);

【讨论】:

【参考方案6】:

对于任何寻求快速简便的解决方案的人,这里有一个插件,可让您通过在可排序参数中指定动画长度来快速添加可排序动画:

$('#sortable').sortable(
 animation: 200,
);

演示:https://egorshar.github.io/jquery-ui-sortable-animation/

Github:https://github.com/egorshar/jquery-ui-sortable-animation

【讨论】:

以上是关于带有动画的 jQuery 可排序的主要内容,如果未能解决你的问题,请参考以下文章

带有独特动画面板的 jQuery 内容滑块

动画完成后带有效果'反弹'的JQuery Animate?

带有下一个的jQuery动画无限循环

jQuery 是不是在两个不同的 CSS 类之间进行动画处理?

左侧带有 z-index 的 Jquery 动画

带有滚动的 Jquery/Javascript 不透明度动画