使用拖放重新排列 HTML 表格行

Posted

技术标签:

【中文标题】使用拖放重新排列 HTML 表格行【英文标题】:Reorder HTML table rows using drag-and-drop 【发布时间】:2011-01-05 13:58:53 【问题描述】:

我有一个 jQuery 函数来上下移动表格行。我不知道如何保存数据,也不知道每一行的位置。我正在使用 php 来显示表格行。

当用户对表格行重新排序时,如何获取每个表格行的位置值?

【问题讨论】:

【参考方案1】:

jQuery UI sortable plugin 提供拖放重新排序。保存按钮可以提取每个项目的 ID,以创建这些 ID 的逗号分隔字符串,添加到隐藏的文本框中。使用异步回发将文本框返回到服务器。

fiddle example 重新排序表元素,但不将它们保存到数据库中。

可排序插件只需一行代码即可将任何列表转换为可排序列表。如果您愿意使用它们,它还提供 CSS 和图像来为可排序列表提供视觉冲击(请参阅我链接到的示例)。但是,开发人员必须提供代码以按新顺序检索项目。我将列表中每个项目的唯一 ID 作为 html 属性嵌入,然后通过 jQuery 检索这些 ID。

例如:

// ----- code executed when the document loads
$(function() 
    wireReorderList();
);

function wireReorderList() 
    $("#reorderExampleItems").sortable();
    $("#reorderExampleItems").disableSelection();


function saveOrderClick() 
    // ----- Retrieve the li items inside our sortable list
    var items = $("#reorderExampleItems li");

    var linkIDs = [items.size()];
    var index = 0;

    // ----- Iterate through each li, extracting the ID embedded as an attribute
    items.each(
        function(intIndex) 
            linkIDs[index] = $(this).attr("ExampleItemID");
            index++;
        );

    $get("<%=txtExampleItemsOrder.ClientID %>").value = linkIDs.join(",");

【讨论】:

如果您更仔细地检查我的示例,代码与您实际对其进行排序的方式无关(在您的情况下,只需查询 tr 而不是 li 来获取您的行)。您可以通过将列表存储为 html 属性然后使用 jquery attr() 以排序顺序检索值来从列表中检索您想要的任何值。我将进一步补充说,我根本不欣赏你的语气。我提供了您所要求的答案,并建议您查看一种非常流行的排序方法,以防您不知道。 您的行 var linkIDs = [items.size()]; 未初始化大小为 items.size() 的数组。您只是在创建一个包含该大小的单个元素的数组。这会在 items.each 的第一次迭代中被覆盖.. Jim,我怎样才能将这个数组保存在数据库 mysql 中?你知道哪里有关于它的教程吗? 效果很好。谢谢。【参考方案2】:

显然这个问题描述了 OP 的问题,但这个问题是拖动以重新排序表行的***搜索结果,所以这就是我要回答的问题。我对为这么简单的事情引入 jQuery UI 不感兴趣,所以这是一个仅 jQuery 的解决方案:

$(".grab").mousedown(function(e) 
  var tr = $(e.target).closest("TR"),
    si = tr.index(),
    sy = e.pageY,
    b = $(document.body),
    drag;
  if (si == 0) return;
  b.addClass("grabCursor").css("userSelect", "none");
  tr.addClass("grabbed");

  function move(e) 
    if (!drag && Math.abs(e.pageY - sy) < 10) return;
    drag = true;
    tr.siblings().each(function() 
      var s = $(this),
        i = s.index(),
        y = s.offset().top;
      if (i > 0 && e.pageY >= y && e.pageY < y + s.outerHeight()) 
        if (i < tr.index())
          tr.insertAfter(s);
        else
          tr.insertBefore(s);
        return false;
      
    );
  

  function up(e) 
    if (drag && si != tr.index()) 
      drag = false;
      alert("moved!");
    
    $(document).unbind("mousemove", move).unbind("mouseup", up);
    b.removeClass("grabCursor").css("userSelect", "none");
    tr.removeClass("grabbed");
  
  $(document).mousemove(move).mouseup(up);
);
.grab 
  cursor: grab;


.grabbed 
  box-shadow: 0 0 13px #000;


.grabCursor,
.grabCursor * 
  cursor: grabbing !important;
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
  <tr>
    <th></th>
    <th>Table Header</th>
  </tr>
  <tr>
    <td class="grab">&#9776;</td>
    <td>Table Cell 1</td>
  </tr>
  <tr>
    <td class="grab">&#9776;</td>
    <td>Table Cell 2</td>
  </tr>
  <tr>
    <td class="grab">&#9776;</td>
    <td>Table Cell 3</td>
  </tr>
</table>

注意si == 0i &gt; 0 忽略第一行,对我来说它包含TH 标签。将 alert 替换为您的“拖动完成”逻辑。

【讨论】:

伟大的工作人员。这让我很快乐。如果有人觉得它有用,这是我的小提琴。 jsfiddle.net/7ko9ay1e 我们如何为多行做到这一点【参考方案3】:

我用得很好

<script>
    $(function () 

        $("#catalog tbody tr").draggable(
            appendTo:"body",
            helper:"clone"
        );
        $("#cart tbody").droppable(
            activeClass:"ui-state-default",
            hoverClass:"ui-state-hover",
            accept:":not(.ui-sortable-helper)",
            drop:function (event, ui) 
                $('.placeholder').remove();
                row = ui.draggable;
                $(this).append(row);
            
        );
    );
</script>

【讨论】:

【参考方案4】:

易于插件 jquery TableDnd

$(document).ready(function() 

    // Initialise the first table (as before)
    $("#table-1").tableDnD();

    // Make a nice striped effect on the table
    $("#table-2 tr:even').addClass('alt')");

    // Initialise the second table specifying a dragClass and an onDrop function that will display an alert
    $("#table-2").tableDnD(
        onDragClass: "myDragClass",
        onDrop: function(table, row) 
            var rows = table.tBodies[0].rows;
            var debugStr = "Row dropped was "+row.id+". New order: ";
            for (var i=0; i<rows.length; i++) 
                debugStr += rows[i].id+" ";
            
            $(table).parent().find('.result').text(debugStr);
        ,
        onDragStart: function(table, row) 
            $(table).parent().find('.result').text("Started dragging row "+row.id);
        
    );
);

插件(TableDnD): https://github.com/isocra/TableDnD/

演示: http://jsfiddle.net/DenisHo/dxpLrcd9/embedded/result/

CDN: https://cdn.jsdelivr.net/jquery.tablednd/0.8/jquery.tablednd.0.8.min.js

【讨论】:

嗨,这个插件也可以和 JSF 一起使用吗?【参考方案5】:

您可能想查看jQuery Sortable。我用它来重新排序表格行。

【讨论】:

谢谢,但你有没有读过我的问题?!我不是在寻找新的 d&d 插件。只是想知道如何解决我当前脚本在获取每一行值时遇到的问题 @Ghazanfari,我在你的问题中看不到任何人都可以解决的脚本。【参考方案6】:

在@tim 的基础上,这个版本收紧了范围和格式,并转换了bind() -> on()。它旨在绑定专用的td 作为句柄而不是整行。在我的用例中,我有 input 字段,因此“拖动行中的任意位置”方法让人感到困惑。

测试在桌面上工作。移动触控仅取得部分成功。由于某种原因,它无法在 SO 的可运行 sn-p 上正确运行...

let ns = 
  drag: (e) => 
    let el = $(e.target),
      d = $('body'),
      tr = el.closest('tr'),
      sy = e.pageY,
      drag = false,
      index = tr.index();

    tr.addClass('grabbed');

    function move(e) 
      if (!drag && Math.abs(e.pageY - sy) < 10)
        return;
      drag = true;
      tr.siblings().each(function() 
        let s = $(this),
          i = s.index(),
          y = s.offset().top;
        if (e.pageY >= y && e.pageY < y + s.outerHeight()) 
          i < tr.index() ? s.insertAfter(tr) : s.insertBefore(tr);
          return false;
        
      );
    

    function up(e) 
      if (drag && index !== tr.index())
        drag = false;

      d.off('mousemove', move).off('mouseup', up);
      //d.off('touchmove', move).off('touchend', up); //failed attempt at touch compatibility
      tr.removeClass('grabbed');
    
    d.on('mousemove', move).on('mouseup', up);
    //d.on('touchmove', move).on('touchend', up);
  
;

$(document).ready(() => 
  $('body').on('mousedown touchstart', '.drag', ns.drag);
);
.grab 
  cursor: grab;
  user-select: none


tr.grabbed 
  box-shadow: 4px 1px 5px 2px rgba(0, 0, 0, 0.5);


tr.grabbed:active 
  user-input: none;


tr.grabbed:active * 
  user-input: none;
  cursor: grabbing !important;
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
  <thead>
    <tr>
      <th></th>
      <th>Drag the rows below...</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td class='grab'>&vellip;</td>
      <td><input type="text" value="Row 1" /></td>
    </tr>
    <tr>
      <td class='grab'>&vellip;</td>
      <td><input type="text" value="Row 2" /></td>
    </tr>
    <tr>
      <td class='grab'>&vellip;</td>
      <td><input type="text" value="Row 3" /></td>
    </tr>
  </tbody>
</table>

【讨论】:

以上是关于使用拖放重新排列 HTML 表格行的主要内容,如果未能解决你的问题,请参考以下文章

通过拖动委托向上或向下拖动一行来重新排列表格中的部分(iOS 11)

使用角材料的拖放重新排列垫表行

通过使用拖动委托向上或向下拖动一行来重新排列表格中的部分(iOS 11)

有没有办法在 devexpress TreeListControl 中通过拖放重新排列节点时预览元素的位置?

PyQt QListView 拖放问题,用于在一个列表中导入和重新排列

在 Angular Material CDK 拖放中,如何防止项目随着元素移动而自动重新排列?