编辑 3: 只是总结一下变成了一个相当长的问题,希望有人会发现它更容易理解它的要点并能够更容易地提供帮助:
我想要的是让下面的jsfiddle#2(在EDIT 2下)工作,因为它应该在选择和拖动时正确地将多个项目放在正确的位置。
原始问题:
我试图弄清楚如何让 nestedSortable 允许选择多个项目。我无法通过谷歌搜索在任何地方找到有关它的任何信息,我自己也无法弄清楚。
如果有人知道如何做到这一点,那就太好了。我一直将其视为如何使用多个项目进行拖放的示例-这本身就很难找到!
jsfiddle #1,通过拖放进行多选,但仅限于平面元素结构:http: //jsfiddle.net/2n9xkmg3/
这里的主要 jQuery 代码:
$(function () {
$('.droptrue').on('click', 'li', function () {
$(this).toggleClass('selected');
});
$("ul.droptrue").sortable({
connectWith: 'ul.droptrue',
opacity: 0.6,
revert: true,
helper: function (e, item) {
console.log('parent-helper');
console.log(item);
if(!item.hasClass('selected'))
item.addClass('selected');
var elements = $('.selected').not('.ui-sortable-placeholder').clone();
var helper = $('<ul/>');
item.siblings('.selected').addClass('hidden');
return helper.append(elements);
},
start: function (e, ui) {
var elements = ui.item.siblings('.selected.hidden').not('.ui-sortable-placeholder');
ui.item.data('items', elements);
},
receive: function (e, ui) {
ui.item.before(ui.item.data('items'));
},
stop: function (e, ui) {
ui.item.siblings('.selected').removeClass('hidden');
$('.selected').removeClass('selected');
},
update: updatePostOrder
});
$("#sortable1, #sortable2").disableSelection();
$("#sortable1, #sortable2").css('minHeight', $("#sortable1").height() + "px");
updatePostOrder();
});
function updatePostOrder() {
var arr = [];
$("#sortable2 li").each(function () {
arr.push($(this).attr('id'));
});
$('#postOrder').val(arr.join(','));
}
我在另一个堆栈溢出问题的评论中找到了该示例的建议:
如何使用 JavaScript 或 jQuery 一次拖动多个元素?
那么我怎样才能让这个多选在nestedSortable 插件中工作呢?
有关该插件的信息,请参阅https://github.com/ilikenwf/nestedSortable。
基本上我想要实现的是在 Web 应用程序中拖放项目(如文件和文件夹,但也可能是其他东西),类似于 DropBox 和 Google Drive 在他们的网络中多次拖放文件和文件夹接口。
除了......我需要这个嵌套,就像在nestedSortable插件中一样。
由于很多网站都有这样的功能,我几乎认为会有一个现成的解决方案,但事实证明,即使是对多个项目的平面结构拖放,也很难找到答案,更不用说与嵌套结构相结合。但是在各种网站上也有很多这样的例子,我只是不知道如何实现它。
非常感谢任何帮助!
编辑:添加了上面插件的链接。
编辑2:
我觉得这个问题需要一个更清晰的例子才能在这个问题上获得帮助。所以我自己创建了一个完整的 jsfiddle。
这个采用了上面提到的 jsfiddle,然后我尝试创建一个新的,基于 nestedSortable 插件示例文件:https ://github.com/ilikenwf/nestedSortable/blob/2.0alpha/example.html
这是我的新jsfiddle:
jsfiddle #2,在嵌套结构中通过拖放尝试多选:
http://jsfiddle.net/anderszvensson/w141dLLt/1/
我从嵌套可排序列表的示例开始。然后我尝试合并来自 jsfiddle #1 的多选(仅处理平面结构的多选拖放)。
到目前为止,我合并的部分只是元素.selected
上的 toggleClass <li>
,还为选择 an 时添加了边框<li>
,以及helper
选项。
这确实使它部分起作用,但不是完全起作用。也就是说,拖动多个元素表明它确实将所有选定的元素都带入了拖动中。
但是,仍然只有一个元素被丢弃/接收。我无法让它实际移动/放下拖动中的所有元素。
我希望这会有所帮助,以便比我更擅长 jQuery 的人能够弄清楚如何使多个元素的拖放在这个 nestedSortable 插件中工作。
为清楚起见,这是来自 jsfiddle #2 的代码(我自己的尝试):
HTML:
<body>
<header>
<h1>nestedSortable jQuery Plugin</h1>
<h2>2.0</h2>
</header>
<section>
<p>This is the demo page for the nestedSortable jQuery plugin.</p>
<p><strong>Follow the development, read the docs and download the
latest version directly from the <a href="https://github.com/ilikenwf/nestedSortable">GitHub
page</a>.</strong></p>
</section><!-- END section -->
<section id="demo">
<ol class="sortable ui-sortable mjs-nestedSortable-branch mjs-nestedSortable-expanded">
<li style="display: list-item;" class="mjs-nestedSortable-branch mjs-nestedSortable-expanded" id="menuItem_2">
<div class="menuDiv">
<span title="Click to show/hide children" class="disclose ui-icon ui-icon-minusthick">
<span></span>
</span>
<span title="Click to show/hide item editor" data-id="2" class="expandEditor ui-icon ui-icon-triangle-1-n">
<span></span>
</span>
<span>
<span data-id="2" class="itemTitle">a</span>
<span title="Click to delete item." data-id="2" class="deleteMenu ui-icon ui-icon-closethick">
<span></span>
</span>
</span>
<div id="menuEdit2" class="menuEdit hidden">
<p>
Content or form, or nothing here. Whatever you want.
</p>
</div>
</div>
<ol>
<li style="display: list-item;" class="mjs-nestedSortable-branch mjs-nestedSortable-expanded" id="menuItem_4">
<div class="menuDiv">
<span title="Click to show/hide children" class="disclose ui-icon ui-icon-minusthick">
<span></span>
</span>
<span title="Click to show/hide item editor" data-id="4" class="expandEditor ui-icon ui-icon-triangle-1-n">
<span></span>
</span>
<span>
<span data-id="4" class="itemTitle">c</span>
<span title="Click to delete item." data-id="4" class="deleteMenu ui-icon ui-icon-closethick">
<span></span>
</span>
</span>
<div id="menuEdit4" class="menuEdit hidden">
<p>
Content or form, or nothing here. Whatever you want.
</p>
</div>
</div>
<ol>
<li class="mjs-nestedSortable-leaf" id="menuItem_6">
<div class="menuDiv">
<span title="Click to show/hide children" class="disclose ui-icon ui-icon-minusthick">
<span></span>
</span>
<span title="Click to show/hide item editor" data-id="6" class="expandEditor ui-icon ui-icon-triangle-1-n">
<span></span>
</span>
<span>
<span data-id="6" class="itemTitle">e</span>
<span title="Click to delete item." data-id="6" class="deleteMenu ui-icon ui-icon-closethick">
<span></span>
</span>
</span>
<div id="menuEdit6" class="menuEdit hidden">
<p>
Content or form, or nothing here. Whatever you want.
</p>
</div>
</div>
</li>
</ol>
</li>
<li style="display: list-item;" class="mjs-nestedSortable-leaf" id="menuItem_5">
<div class="menuDiv">
<span title="Click to show/hide children" class="disclose ui-icon ui-icon-minusthick">
<span></span>
</span>
<span title="Click to show/hide item editor" data-id="5" class="expandEditor ui-icon ui-icon-triangle-1-n">
<span></span>
</span>
<span>
<span data-id="5" class="itemTitle">d</span>
<span title="Click to delete item." data-id="5" class="deleteMenu ui-icon ui-icon-closethick">
<span></span>
</span>
</span>
<div id="menuEdit5" class="menuEdit hidden">
<p>
Content or form, or nothing here. Whatever you want.
</p>
</div>
</div>
</li>
</ol>
</li>
<ol>
</ol>
<li style="display: list-item;" class="mjs-nestedSortable-leaf" id="menuItem_7">
<div class="menuDiv">
<span title="Click to show/hide children" class="disclose ui-icon ui-icon-minusthick">
<span></span>
</span>
<span title="Click to show/hide item editor" data-id="7" class="expandEditor ui-icon ui-icon-triangle-1-n">
<span></span>
</span>
<span>
<span data-id="7" class="itemTitle">f</span>
<span title="Click to delete item." data-id="7" class="deleteMenu ui-icon ui-icon-closethick">
<span></span>
</span>
</span>
<div id="menuEdit7" class="menuEdit hidden">
<p>
Content or form, or nothing here. Whatever you want.
</p>
</div>
</div>
</li>
<li class="mjs-nestedSortable-leaf" id="menuItem_3">
<div class="menuDiv">
<span title="Click to show/hide children" class="disclose ui-icon ui-icon-minusthick">
<span></span>
</span>
<span title="Click to show/hide item editor" data-id="3" class="expandEditor ui-icon ui-icon-triangle-1-n">
<span></span>
</span>
<span>
<span data-id="3" class="itemTitle">b</span>
<span title="Click to delete item." data-id="3" class="deleteMenu ui-icon ui-icon-closethick">
<span></span>
</span>
</span>
<div id="menuEdit3" class="menuEdit hidden">
<p>
Content or form, or nothing here. Whatever you want.
</p>
</div>
</div>
</li>
</ol>
<h3>Try the custom methods:</h3>
<p><br>
<input id="serialize" name="serialize" type="submit" value=
"Serialize"></p>
<pre id="serializeOutput">
</pre>
<p><input id="toArray" name="toArray" type="submit" value=
"To array"></p>
<pre id="toArrayOutput">
</pre>
<p><input id="toHierarchy" name="toHierarchy" type="submit" value=
"To hierarchy"></p>
<pre id="toHierarchyOutput">
</pre>
<p><em>Note: This demo has the <code>maxLevels</code> option set to '4'.</em></p>
</section><!-- END #demo -->
<section id="license">
<h4>License</h4>
<p>This work is licensed under the MIT License.<br>
Which means you can do pretty much whatever you want with it.</p>
<p>© 2010‐2014 Manuele J Sarfatti</p>
</section><!-- END #documentation -->
</body>
JS:
$().ready(function(){
$('li.mjs-nestedSortable-leaf').on('click', function () {
$(this).toggleClass('selected');
});
var ns = $('ol.sortable').nestedSortable({
forcePlaceholderSize: true,
handle: 'div',
helper: function (e, item) {
console.log('parent-helper');
console.log(item);
if(!item.hasClass('selected'))
item.addClass('selected');
var elements = $('.selected').not('.ui-sortable-placeholder').clone();
var helper = $('<ul/>');
item.siblings('.selected').addClass('hidden');
return helper.append(elements);
},
start: function (e, ui) {
var elements = ui.item.siblings('.selected.hidden').not('.ui-sortable-placeholder');
ui.item.data('items', elements);
},
receive: function (e, ui) {
ui.item.before(ui.item.data('items'));
},
stop: function (e, ui) {
ui.item.siblings('.selected').removeClass('hidden');
$('.selected').removeClass('selected');
},
items: 'li',
opacity: .6,
placeholder: 'placeholder',
revert: 250,
tabSize: 25,
tolerance: 'pointer',
toleranceElement: '> div',
maxLevels: 4,
isTree: true,
expandOnHover: 700,
startCollapsed: false,
change: function(){
console.log('Relocated item');
}
});
$('.expandEditor').attr('title','Click to show/hide item editor');
$('.disclose').attr('title','Click to show/hide children');
$('.deleteMenu').attr('title', 'Click to delete item.');
$('.disclose').on('click', function() {
$(this).closest('li').toggleClass('mjs-nestedSortable-collapsed').toggleClass('mjs-nestedSortable-expanded');
$(this).toggleClass('ui-icon-plusthick').toggleClass('ui-icon-minusthick');
});
$('.expandEditor, .itemTitle').click(function(){
var id = $(this).attr('data-id');
$('#menuEdit'+id).toggle();
$(this).toggleClass('ui-icon-triangle-1-n').toggleClass('ui-icon-triangle-1-s');
});
$('.deleteMenu').click(function(){
var id = $(this).attr('data-id');
$('#menuItem_'+id).remove();
});
$('#serialize').click(function(){
serialized = $('ol.sortable').nestedSortable('serialize');
$('#serializeOutput').text(serialized+'\n\n');
})
$('#toHierarchy').click(function(e){
hiered = $('ol.sortable').nestedSortable('toHierarchy', {startDepthCount: 0});
hiered = dump(hiered);
(typeof($('#toHierarchyOutput')[0].textContent) != 'undefined') ?
$('#toHierarchyOutput')[0].textContent = hiered : $('#toHierarchyOutput')[0].innerText = hiered;
})
$('#toArray').click(function(e){
arraied = $('ol.sortable').nestedSortable('toArray', {startDepthCount: 0});
arraied = dump(arraied);
(typeof($('#toArrayOutput')[0].textContent) != 'undefined') ?
$('#toArrayOutput')[0].textContent = arraied : $('#toArrayOutput')[0].innerText = arraied;
});
});
function dump(arr,level) {
var dumped_text = "";
if(!level) level = 0;
//The padding given at the beginning of the line.
var level_padding = "";
for(var j=0;j<level+1;j++) level_padding += " ";
if(typeof(arr) == 'object') { //Array/Hashes/Objects
for(var item in arr) {
var value = arr[item];
if(typeof(value) == 'object') { //If it is an array,
dumped_text += level_padding + "'" + item + "' ...\n";
dumped_text += dump(value,level+1);
} else {
dumped_text += level_padding + "'" + item + "' => \"" + value + "\"\n";
}
}
} else { //Strings/Chars/Numbers etc.
dumped_text = "===>"+arr+"<===("+typeof(arr)+")";
}
return dumped_text;
}
CSS:
html {
background-color: #eee;
}
body {
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
color: #444;
background-color: #fff;
font-size: 13px;
font-family: Freesans, sans-serif;
padding: 2em 4em;
width: 860px;
margin: 15px auto;
box-shadow: 1px 1px 8px #444;
-mox-box-shadow: 1px 1px 8px #444;
-webkit-box-shadow: 1px -1px 8px #444;
}
a,a:visited {
color: #4183C4;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
pre,code {
font-size: 12px;
}
pre {
width: 100%;
overflow: auto;
}
small {
font-size: 90%;
}
small code {
font-size: 11px;
}
.placeholder {
outline: 1px dashed #4183C4;
}
.mjs-nestedSortable-error {
background: #fbe3e4;
border-color: transparent;
}
#tree {
width: 550px;
margin: 0;
}
ol {
max-width: 450px;
padding-left: 25px;
}
ol.sortable,ol.sortable ol {
list-style-type: none;
}
.sortable li div {
border: 1px solid #d4d4d4;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
cursor: move;
border-color: #D4D4D4 #D4D4D4 #BCBCBC;
margin: 0;
padding: 3px;
}
li.mjs-nestedSortable-collapsed.mjs-nestedSortable-hovering div {
border-color: #999;
}
.disclose, .expandEditor {
cursor: pointer;
width: 20px;
display: none;
}
.sortable li.mjs-nestedSortable-collapsed > ol {
display: none;
}
.sortable li.mjs-nestedSortable-branch > div > .disclose {
display: inline-block;
}
.sortable span.ui-icon {
display: inline-block;
margin: 0;
padding: 0;
}
.menuDiv {
background: #EBEBEB;
}
.menuEdit {
background: #FFF;
}
.itemTitle {
vertical-align: middle;
cursor: pointer;
}
.deleteMenu {
float: right;
cursor: pointer;
}
h1 {
font-size: 2em;
margin-bottom: 0;
}
h2 {
font-size: 1.2em;
font-weight: 400;
font-style: italic;
margin-top: .2em;
margin-bottom: 1.5em;
}
h3 {
font-size: 1em;
margin: 1em 0 .3em;
}
p,ol,ul,pre,form {
margin-top: 0;
margin-bottom: 1em;
}
dl {
margin: 0;
}
dd {
margin: 0;
padding: 0 0 0 1.5em;
}
code {
background: #e5e5e5;
}
input {
vertical-align: text-bottom;
}
.notice {
color: #c33;
}
.selected {
border: solid #000 1px;
}