【问题标题】:JQuery sortable list with some elements frozen in order?JQuery 可排序列表,其中一些元素按顺序冻结?
【发布时间】:2012-02-16 20:19:59
【问题描述】:

我正在寻找一种方法来获得类似 JQuery 的可排序列表 (link),但其中一些元素位于固定的不可拖动位置。

使某些元素不可拖动很简单,但它们的位置不会保持固定,因为它们上方和下方的可拖动元素的数量可以改变。

更具体地说: 我有一个按等级排列的 10 个项目的列表。我希望用户能够通过拖动(可排序列表)来更改某些项目的排名,但不能更改其他冻结元素的排名。标准的 JQuery 可排序不可拖动功能允许通过更改冻结项上方或下方的元素数量来更改冻结项的排名。

我尝试在拖动时通过“交换”列表元素手动执行此操作。即,当一个列表元素被拖动到一个非冻结元素上时,两个元素的位置被交换。这给出了我想要的语义,但是被拖动的项目明显地在其新位置和当前“拖动”位置之间“跳跃”。 (我希望它保持在当前的拖动位置;只有它在 DOM 中的位置应该改变。但是当 DOM 位置改变时,必须重新计算拖动偏移坐标。而且我不知道如何同时改变 DOM 位置并拖动偏移坐标原子地更改,防止两者之间重绘。目前,有时两者之间会发生重绘,并且元素明显(尽管很短)跳跃。)

编辑 这是一个显示我的手动方法的 jsfiddle: link。玩一会儿,你会注意到我提到的闪烁/跳跃。

【问题讨论】:

  • 您是否尝试将您的行为绑定到beforeStop 事件?
  • 这听起来很有趣,我猜你已经有了一些几乎可以工作的代码?请考虑用你所拥有的创建一个 jsfiddle!
  • @LinusGThiel,我添加了一个指向显示我手动尝试的 jsfiddle 的链接。
  • @graphicdivine,你能扩展一下吗?我应该在beforeStop 上添加什么行为?

标签: javascript jquery jquery-ui


【解决方案1】:

我看过你的小提琴,有另一个想法,这是使用sortable 的一种方法:在start 上将固定索引位置存储在每个固定项目的data 对象中,然后在任何change,将固定项目移回原位。

$(function() {   
    $('#rankings').sortable({
        axis: 'y',
        items: '.sortable',
        start: function () {
            $(this).find("li:not(.sortable)").each(function () {
                $(this).data("fixedIndex", $(this).index());
            });
        },        
        change: function () {
            $(this).find("li:not(.sortable)").each(function () {
                $(this).detach().insertAfter($("#rankings li:eq(" + ($(this).data("fixedIndex")-1) + ")"));
            });
        }
    });
});

使用如下列表:

<ol id="rankings">
    <li class="sortable">Dog</li>
    <li class="">Cat</li>
    <li class="sortable">Parrot</li>
    <li class="sortable">Gerbil</li>
    <li class="sortable">Snake</li>
    <li class="">Goldfish</li>
</ol>

Seems to work

【讨论】:

  • 我想为了提高效率,您可能还想在分离和移动它们之前检查不可排序的项目是否不合适
  • 不错;这是迄今为止最干净的解决方案。所有的改组都会导致偶尔出现口吃,但对于小列表来说,这并不太明显。
  • 如果列表中的第一项不可排序,则会失败,因为您将尝试 insertAfter 索引 -1。 This answer 添加一个虚拟元素。伊克。
  • 更简单的解决方案:只需检查 fixedIndex 0 并跳过它。 Sortable 首先不会移动该元素。对 fixedIndex == $(this).index() 的检查做同样的事情。
  • +1。出色的。解决了我的问题。我实际上只是在寻找 items: '.sortable' 部分,但整个解决方案非常有趣。
【解决方案2】:

我想我可能已经破解了它 - http://jsfiddle.net/q5c4Y/3/。虽然是一个很大的挑战。在此过程中有些事情有所帮助

  • 使用更结构化的标记
  • 使用 droppable 的 over 事件来交换列表项,而不是 drop 事件(使用 dragstop 代替)
  • 在内部项目上设置一些定位,以便在更改其父元素后将它们保持在正确的位置

虽然,阅读上面@graphicdivine 的回答,看起来你真正需要的是 jquery ui sortable

【讨论】:

  • 有趣。这个解决方案仍然有些破损,因为一个项目不能轻易地拖回它的初始位置。当项目“A”被拖到项目“B”上时,“B”移动到“A”旧位置。但是,将“A”移回“B”上并不会将“B”返回到其原始位置。这可能是可以修复的,但我还没有查看代码。
【解决方案3】:

1) 如果您不想更改的项目都在列表的顶部和/或底部,您可以在列表之外创建这些项目,从而只允许对其他项目进行排序并保留排名不可变的。

2) 你可以使用“停止”事件来检查你想要的排名是否被保留了?即,检查是否仍然只有 3 个项目高于第 4 排名项目,如果没有,将新的“第 4”移动到具有第 4 不可变排名的项目之下?基本上,在物品被拖到非法地点后强制重新转移物品?

【讨论】:

  • (1) 不是一个选项;冷冻物品可以出现在中间。 (2) 是一个选项,虽然我担心重新调整会导致的闪烁量。即使是简单的交换方法也很明显。
  • 我绝对听说过...对于更平滑的过渡,项目轻轻地进入新位置,您感觉如何?我意识到这并不理想......会继续思考......这是一个有趣的问题!
  • 如果不是进行硬交换(如在您的 jsfiddle 示例中),那么您做了一个平滑的转换呢?慢慢地将要移位的项目滑到新位置,并使用放置处理程序允许将新项目放置到该位置?
  • 我认为如果冻结的项目总是在最后,选项1是最好的解决方案。因为 drop 占位符不会对用户撒谎,并且会减少检查。但当然,前提是冻结的项目必须在末尾。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-06-27
  • 2023-03-08
  • 2017-01-07
  • 1970-01-01
  • 2020-06-29
  • 1970-01-01
  • 2012-01-16
相关资源
最近更新 更多