Knockout嵌套可排序列表

我需要构建一个包含两个可以交换的列表的网页。 列表中的项目也可以从一个列表交换或移动到另一个列表。

我使用knockoutjs和knockoutjs-sortable来实现这一点。

HTML

JS

 var Task = function (name) { this.name = ko.observable(name); } var ViewModel = function () { var self = this; self.tasks1 = ko.observableArray([]); self.tasks2 = ko.observableArray([]); for (var i = 0; i < 5; i++) { self.tasks1.push(new Task("This task belongs to list one")); self.tasks2.push(new Task("This task belongs to list two")); } self.TaskList1 = { Tasks: self.tasks1, Title: 'List One' }; self.TaskList2 = { Tasks: self.tasks2, Title: 'List Two' }; self.TaskLists = ko.observableArray([]); self.TaskLists.push(self.TaskList1); self.TaskLists.push(self.TaskList2); }; ko.bindingHandlers.sortable.options = { placeholder: 'ui-state-highlight', start: function (e, ui) { var dragElements = $('.ui-state-highlight'); dragElements.css("height", ui.helper.outerHeight()); } }; ko.applyBindings(new ViewModel()); 

CSS

 .frame { padding: 10px; overflow:auto; } .item { border: black 1px solid; width: 100px; background-color: #DDD; cursor: move; text-align: center; margin-top: 2px; margin-bottom: 2px; } .taskList { width: 110px; float:left; background: lightgreen; } .Tasks { width:400px; border: 1px #eee solid; height: 100%; } .taskName { word-wrap: break-word; } .ui-state-highlight { background: grey; border:1px dashed grey; } 

这是我到目前为止所得到的(小提琴) 。

一切都按预期工作,除了移动列表。 移动列表时,我希望拖拽式占位符看起来像:

在此处输入图像描述

但我得到的是:

在此处输入图像描述

我究竟做错了什么? 我怎样才能达到这些预期的效果?

睡个好觉后我发现了问题。 我的设计上面有几个陷阱:

  • 嵌套列表没有connectClass ,它将帮助knockout-sortable找出可以拖动元素的位置。 如果没有指定,则其中一个列表会接受要拖入其中的项目或完整列表。
  • 可拖动的占位符具有与列表本身不同的样式。 这就是为什么可拖动占位符未正确呈现的原因(参考上面我的问题中的结果截图)
  • 只定义了一个占位符,它既适用于拖动项目,也适用于拖动列表,这是不好的。

这是一个显示完整工作解决方案的小提琴 。

HTML

 

JS

 var Task = function(name) { this.name = ko.observable(name); } var ViewModel = function() { var self = this; self.tasks1 = ko.observableArray([]); self.tasks2 = ko.observableArray([]); for (var i=0;i<5;i++){ self.tasks1.push(new Task("This task belongs to list one")); self.tasks2.push(new Task("This task belongs to list two")); } self.TaskList1 = {Tasks: self.tasks1, Title:'List One'}; self.TaskList2 = {Tasks: self.tasks2, Title:'List Two'}; self.TaskLists = ko.observableArray([]); self.TaskLists.push(self.TaskList1); self.TaskLists.push(self.TaskList2); }; ko.bindingHandlers.sortable.options = { //placeholder: 'ui-state-highlight', start: function (e, ui) { var dragItems = $('.ui-state-highlight'); var dragLists = $('.list-highlight'); var elementClass = ui.helper[0].className; if(elementClass === "item") dragItems.css("height",ui.helper.outerHeight()); if(elementClass === "taskList") dragLists.css("height",ui.helper.outerHeight()); } }; ko.applyBindings(new ViewModel()); 

CSS

  .frame{ padding: 10px; overflow:auto; } .item { border: black 1px solid; width: 100px; background-color: #DDD; cursor: move; text-align: center; margin-top: 2px; margin-bottom: 2px; } .list-highlight{ width: 100px; float:left; background: gray; } .taskList{ width: 110px; float:left; background: lightgreen; } .Tasks{ width:400px; border: 1px #eee solid; height: 100%; } .taskName{ word-wrap: break-word; } .ui-state-highlight{ background: grey; border:1px dashed grey; }