jQueryUI Sortable - 使两个可排序列表同时移动

4

我正在使用谷歌CDN提供的jQuery 1.7和jQuery UI 1.8(因此我拥有最新版本)。

我的页面上有两个元素,一个是页眉导航,另一个是内容区域,其中包含与每个页眉列表项对应的容器。目前,我已经将Sortable附加到这两个元素上,使我能够分别重新排列导航元素和内容容器的视觉顺序。我想实现的行为是,当我拖动导航元素时,内容容器也会随之移动,并且当我在列表中的新位置放置导航元素时,内容容器也会粘着其在内容区域中的新位置。我正在处理的网站是一个内部网页,因此我无法提供链接,但我已经在下面包含了一个图表:

Navigation:
NavOne...NavTwo...NavThree
Content:
ContentOne...ContentTwo...ContentThree

在将NavThree拖动到NavOne和NavTwo之间后,整个排列应该看起来像这样:
Navigation:
NavOne...NavThree...NavTwo
Content:
ContentOne...ContentThree...ContentTwo

有没有一种简单的方法将两个Sortable链接起来,使它们以这种方式运作?它并不一定需要平滑或“实时”(虽然我真的希望它可以)。在第一个列表中重新排序完成(放置)之前,我可以接受第二个可排序列表不刷新的情况。
我已经在jQuery UI论坛上询问了这个问题,并等待了一个星期的回复:[LINK]
这是我在测试这个项目之前用的样本框架:
<!DOCTYPE html>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<html>
<head>
<link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css" rel="stylesheet" type="text/css"/>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js"></script>
<style>
/* This is my CSS */
/* Basic reset -- outline for debugging */
* {padding: 0px; margin: 0px; outline: 1px solid rgba(0,0,0,0.1);}
html {width: 100%; height: 100%;}
body {width: 100%; height: 100%;}
/* Main styles */
.containerDiv {
  overflow-x: scroll;
  overflow-y: hidden;
  width: 800px;
  height: 600px;
  white-space: nowrap;
  float: left;
}
.itemDiv {
  width: 200px;
  height: 500px;
  display: inline-block;
}
.navBar ul, .navBar li {
  display: inline;
}
</style>
</head>
<body>
<!-- This is my HTML -->
<div class="navBar">
  <ul>
    <li id="nav1">Navigation 1</li>
    <li id="nav2">Navigation 2</li>
    <li id="nav3">Navigation 3</li>
  </ul>
</div>
<div class="containerDiv">
  <div class="itemDiv" id="item1">Item 1</div>
  <div class="itemDiv" id="item2">Item 2</div>
  <div class="itemDiv" id="item3">Item 3</div>
</div>
</body>
<script>
/* This is my JavaScript */
// Make containerDiv children sortable on X-axis
$(".containerDiv").sortable({
  axis: "x"
});
// Make nav children sortable on x-axis
$(".navBar").sortable({
  axis: "x",
  items: "li"
});
// Bind sorting of each (.navBar li) to its corresponding (.containerDiv .itemDiv):
$(".navBar li").bind("mouseup", function(event,ui){
// If I use "sortupdate" I get little to no response. If I use "mouseup",
// I can at least get an alert to return the value of thisId.
// Note: I am sad that console.log is blocked in Firefox,
// because its DOM inspector is better than Chrome's
  // the (.navBar li) have ids of "nav1, nav2" and so on,
  // and the (.containerDiv .itemDiv) have corresponding ids of "item1, item2"
  // which is my way of attempting to make it easier to link them.
  // This line is my attempt to target the (.containerDiv .itemDiv) which directly
  // corresponds to the (.navBar li) which is currently being sorted:
  var tempId = "#" + $(this).attr('id').replace("nav","item");
  // When this (.navBar li) is updated after a sort drag,
  // trigger the "sortupdate" event on the corresponding (.containerDiv .itemDiv):
  $(tempId).trigger("sortupdate");
});
</script>
</html>

在那一周里,我尝试了许多不同的可能解决方案,但都没有完全达到我想要的效果。我觉得这应该相对简单,但在这一个星期(断断续续)的工作中,我还没有取得任何有用的进展。
在寻找一些见解时,我已经阅读了以下相关主题: 我认为,如果一切都失败了,我至少可以对可排序的内容进行序列化,将其ajax到服务器,然后根据序列化的数据更新第二个列表,但我希望将其保留在本地浏览器上以减少对服务器的调用(直到用户选择将新排列保存到他们的帐户为止)。
因此,StackOverflow...我试图完成的这项任务是否合理/可实现,还是我只是在碰壁? 如果可能,我想避免修改Sortable插件,但如果必须,我会这样做。
我从未使用过jsFiddle,但我意识到它可能有所帮助,所以在这里:http://jsfiddle.net/34u7n/1/
3个回答

1
据我所知,jQuery UI Sortable没有内置的方法或模块可用,因此我编写了自己的jQuery代码来模拟这种功能。
只有在您想要基于一个主列表同步多个可排序列表并且所有列表具有相等数量的项目时,此解决方案才有效。也许它也可以做到双向同步/移动,但我没有尝试过。
<ul class="MasterList">
    <li>one</li>
    <li>two</li>
    <li>three</li>
</ul>

<ul class="SecondList">
    <li>one</li>
    <li>two</li>
    <li>three</li>
</ul>

<ul class="ThirdList">
    <li>one</li>
    <li>two</li>
    <li>three</li>
</ul>


$( '.MasterList' ).sortable
({
    start: function( event, ui )
    {
        // Store start order of the sorting element
        ui.item.OrderStart = ui.item.index();
    },
    stop: function( event, ui )
    {
        // Total number of sorting element
        var OrderTotal = $( '#ObjectiveListSortable li' ).length - 1;
        // Store drop order of the sorting element
        ui.item.OrderStop = ui.item.index();

        // Only do the element sync if there is any change of order. If you simply drag and drop the element back to same position then this prevent such cases.
        if ( ui.item.OrderStart != ui.item.OrderStop )
        {
            // Sorting element dropped to top
            if ( ui.item.OrderStop == 0 )
            {
                $( '.SecondList' ).eq( 0 ).before( $( '.SecondList' ).eq( ui.item.OrderStart ) );
                $( '.ThirdList' ).eq( 0 ).before( $( '.ThirdList' ).eq( ui.item.OrderStart ) );
            }
            // Sorting element dragged from top or dropped to bottom
            else if ( ui.item.OrderStart == 0 || ui.item.OrderStop == OrderTotal )
            {
                $( '.SecondList' ).eq( ui.item.OrderStop ).after( $( '.SecondList' ).eq( ui.item.OrderStart ) );
                $( '.ThirdList' ).eq( ui.item.OrderStop ).after( $( '.ThirdList' ).eq( ui.item.OrderStart ) );
            }
            else
            {
                $( '.SecondList' ).eq( ui.item.OrderStop - 1 ).after( $( '.SecondList' ).eq( ui.item.OrderStart ) );
                $( '.ThirdList' ).eq( ui.item.OrderStop - 1 ).after( $( '.ThirdList' ).eq( ui.item.OrderStart ) );
            }
        }
    }
});

同步完成后,您还可以在次要列表上触发事件$( '.SecondList' ).trigger( 'refresh' );,以便可排序小部件识别通过编程完成的项目顺序更改。

0
排序更新不起作用的原因是您试图将sortupdate事件附加到列表中的每个项目。 sortupdate不会在列表中的每个项目上触发,而是在列表本身上触发,您可以将事件附加到整个列表并获取移动的项目,如下所示。
$(".navBar").sortable({
  axis: "x",
  items: "li",
  update: function(event, ui) { onSort(event, ui); }
});

//this should now at least be firing when you move an item 
function onSort(event, ui)
{
    var tempId = $(ui.item).attr('id').replace("nav","item");
    alert(tempId);
}

我尝试了一下,它确实会产生一个警报。当我试图使用它来触发.itemDiv上的sortupdate时,似乎没有效果。我甚至附加了一个匿名函数来调用alert,当.itemDiv上的update事件触发时,它可以正常工作,但是当通过$(tempId).trigger("sortupdate")$(tempId).trigger("update")从onSort函数调用时,它不会触发。我错过了什么吗? http://jsfiddle.net/adriantp/v88QS/1/ - Adrian
1
我不明白为什么您期望在其他列表中的项上调用 sortupdate,就能将其移到所需位置。我想您需要检查最近移动的项目的新位置,并设置相应项目的位置为该新位置。不确定是否只是我不熟悉 jQuery,但我不明白它如何通过调用 sortupdate 来知道要移动的位置。 - Servy
我也不知道为什么我期望它会这样做。反思之后,这是没有意义的;事件是作为行动的结果而触发的,而不是反过来。 我想我的选择要么是序列化导航栏并使用序列化数据(通过另一个函数)重新排序内容项,要么是扩展可排序插件,以允许我传递新顺序并引起可排序的更新/刷新。 - Adrian
这看起来恰好符合我的使用情况!您在此期间是否已经接近一个可行的解决方案? - rvdb

0
如果有人仍在寻找此内容,这里提供一个可用的示例,希望能对您有所帮助。

var index_start = 0;
var index_stop = 0;
var swap_element = 0;
var picked_element = 0;
$(document).ready(function() {
  $('#list1').sortable({
    start: function(event, ui) {
      index_start = ui.item.index(); //getting index of picked element
    },
    update: function(event, ui) {
      index_stop = ui.item.index(); //getting index where element is dropped
      /*Below steps will fetch the elements from List1 based on original Index ofpicked element in List2
       and its dropped Index position*/
      picked_element = $('.l2:eq(' + index_start + ')');
      swap_element = $('.l2:eq(' + index_stop + ')');

      swap_element.replaceWith(picked_element);
      //replaceWith method of javascript removes the picked_element from its original    
      //position & replaces swap_element with picked_element
      if (index_start > index_stop)
        picked_element.after(swap_element);
      else
        picked_element.before(swap_element);
    },
  });
});
#list2{
  width:20%;
  float:left;
  padding:10px;
}
#list2 .l1 {
  background-color:rgba( 0,0,0,0.2 );
}

#list1{
  width:30%;
  padding:10px;
  float:left;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.13.2/jquery-ui.js"></script>
<div id="list1">
  <div class="l1">One</div>
  <div class="l1">Two</div>
  <div class="l1">Three</div>
  <div class="l1">Four</div>
  <div class="l1">Five</div>
  <div class="l1">Six</div>
</div>
<div id="list2">
  <div class="l2">One</div>
  <div class="l2">Two</div>
  <div class="l2">Three</div>
  <div class="l2">Four</div>
  <div class="l2">Five</div>
  <div class="l2">Six</div>
</div>

源代码


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接