使用可排序的 jQuery UI 对多个表行进行排序

Posted

技术标签:

【中文标题】使用可排序的 jQuery UI 对多个表行进行排序【英文标题】:Sorting multiple table rows with jQuery UI sortable 【发布时间】:2016-06-19 12:01:27 【问题描述】:

我正在使用 jQuery UI 附带的可排序功能来重新排序表格行。它工作正常,这里是JSFiddle,下面是我的 html 和 JS

<table style="width: 100%;">
  <thead>
    <tr>
      <th>ID</th>
      <th>Fruit</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>1</td>
      <td>Apple</td>
    </tr>
      <tr>
      <td>2</td>
      <td>Pear</td>
    </tr>
    <tr class="sticky">
      <td>3</td>
      <td>Banana</td>
    </tr>
      <tr>
      <td>4</td>
      <td>Raspberry</td>
    </tr>
      <tr>
      <td>5</td>
      <td>Mango</td>
    </tr>
  </tbody>
</table>


$(function()
    $("table tbody").sortable();
);

但是我希望我能够同时拖动多行。基本上,当您拖动tr 时,如果其正下方的tr 具有sticky 类,则需要将tr 与它一起拖动。因此,在我的示例中,任何时候您想要拖动并重新排列“Pear”行,下方的“Banana”行都会随之移动。

我认为可以使用辅助函数来执行此操作,但我真的不确定从哪里开始。如果有人可以建议我最好的方法并指出我正确的方向,那就太好了。

【问题讨论】:

我有一个可行的解决方案,但它不会为“粘性”tr 设置动画。您希望粘性项目与拖动的项目一起动画吗? @Yass 理想情况下是的,但是没有动画的解决方案总比没有解决方案好。如果你展示你到目前为止所做的事情,我也许可以做动画部分 好的。我也对动画方面进行了排序。 【参考方案1】:

您可以使用start 事件检查下一个tr 是否具有stickyclass,并将其插入到stop 事件上的拖动项目之后。我正在使用css 方法为“粘性”项目设置动画。

$(function() 
  var $draggedItem, $stickyItem, itemWidth, itemHeight;
  $("table tbody").sortable(
    start: function(event, ui) 
      $draggedItem = $(ui.item[0]);
      //Store the constant width and height values in variables.
      itemWidth = $draggedItem.width();
      itemHeight = $draggedItem.height();
      //next is called twice because a hidden "tr" is added when sorting.
      var $nextChild = $(ui.item[0]).next().next();
      if ($nextChild.hasClass('sticky')) 
        $stickyItem = $nextChild;
      
      else 
        $stickyItem = undefined;
      
    ,
    sort: function() 
      if ($stickyItem != undefined) 
        //Set the css to match the dragged item's css, with the exception of "top", which includes an offset.
        $stickyItem.css(
          "z-index": $draggedItem.css('z-index'),
          "position": "absolute",
          "width": itemWidth,
          "height": itemHeight,
          "left": $draggedItem.css('left'),
          "top": $draggedItem.position().top + itemHeight,
        );
      
    ,
    stop: function() 
      if ($stickyItem != undefined) 
        $stickyItem.insertAfter($draggedItem);
        //Remove the style attribute to reset to thed default style.
        $stickyItem.removeAttr('style');
      
    
  );
);

Fiddle Demo

注意:如果存在粘性项目,您可以通过仅绑定 sortstop 事件来进一步改进上述内容。

【讨论】:

非常感谢您的回答。我必须添加一点以确保您不能在粘性行和它上面的行之间拖动另一行。但是你的评论很好的解决方案让我很容易理解 @Pattle 你能分享一下你添加的那些行吗! @Pattle 请分享您添加的那些额外代码行!我陷入了类似的境地:( @Pattle 来吧!请显示您更改的内容。我也有同样的问题。【参考方案2】:

对于那些想要防止在粘性行和它上面的行之间插入行的人,这里是 Yass 解决方案的略微修改版本:

$(function () 
    let $draggedItem, $stickyItem, itemWidth, itemHeight, cancelSortable;
    $("table tbody").sortable(
        start: function (event, ui) 
            $draggedItem = $(ui.item[0]);
            //Store the constant width and height values in variables.
            itemWidth = $draggedItem.width();
            itemHeight = $draggedItem.height();
            //next is called twice because a hidden "tr" is added when sorting.
            let $nextChild = $(ui.item[0]).next().next();
            if ($nextChild.hasClass('sticky')) 
                $stickyItem = $nextChild;
             else 
                $stickyItem = undefined;
            
        ,
        sort: function (event, ui) 
            if ($stickyItem !== undefined) 
                //Set the css to match the dragged item's css, with the exception of "top", which includes an offset.
                $stickyItem.css(
                    "z-index": $draggedItem.css('z-index'),
                    "position": "absolute",
                    "width": itemWidth,
                    "height": itemHeight,
                    "left": $draggedItem.css('left'),
                    "top": $draggedItem.position().top + itemHeight,
                );
            
            if (ui.placeholder.next() !== undefined && ui.placeholder.next().hasClass("sticky")) 
                ui.placeholder.hide();
                cancelSortable = true;
             else 
                ui.placeholder.show();
                cancelSortable = false;
            
        ,
        stop: function () 
            if (cancelSortable) 
                $(this).sortable("cancel");
            
            if ($stickyItem !== undefined) 
                $stickyItem.insertAfter($draggedItem);
                //Remove the style attribute to reset to the default style.
                $stickyItem.removeAttr('style');
            
        
    );
);

【讨论】:

以上是关于使用可排序的 jQuery UI 对多个表行进行排序的主要内容,如果未能解决你的问题,请参考以下文章

如何在 jQuery UI 中将多个可排序列表相互连接?

使用带有 HTML 表格的 jQuery UI 可排序

没有 HTML 表单的 Laravel 5 AJAX 排序顺序数据(jQuery 可排序)

在 django 模板中使用带有隐藏表行的 jQuery 可排序

jQuery.repeater 不适用于可排序的 jQuery Ui

如何在使用 jquery ui 删除时对元素进行排序?