JQuery Sortable - выбор и перетаскивание нескольких элементов списка
У меня есть проект, где у меня есть список доступных ящиков, пользователи берут коробки, перетаскивая их из списка доступных ящиков в свой список "Мои боксы".
Пользователи чаще всего принимают по несколько ящиков одновременно (макс. 20), после того, как они закончили с полями, которые они перетаскивают обратно в список доступных ящиков, чтобы вернуть их.
jQuery sortable позволяет мне перетаскивать одну ячейку за раз, которая с точки зрения пользователя нежелательна. Я не смог придумать простое решение проблемы.
Мне, возможно, придется придумать другой метод пользовательского интерфейса, но сначала у кого-нибудь есть предложения о том, как это можно сделать?
Спасибо!
Ответы
Ответ 1
У меня нет этой работы, используя сортировку, но я использовал draggable и droppable. Я не знаю, покрыл ли я всю необходимую функциональность, но это должно быть хорошее начало (демонстрация здесь):
HTML
<div class="demo">
<p>Available Boxes (click to select multiple boxes)</p>
<ul id="draggable">
<li>Box #1</li>
<li>Box #2</li>
<li>Box #3</li>
<li>Box #4</li>
</ul>
<p>My Boxes</p>
<ul id="droppable">
</ul>
</div>
Script
$(document).ready(function(){
var selectedClass = 'ui-state-highlight',
clickDelay = 600, // click time (milliseconds)
lastClick, diffClick; // timestamps
$("#draggable li")
// Script to deferentiate a click from a mousedown for drag event
.bind('mousedown mouseup', function(e){
if (e.type=="mousedown") {
lastClick = e.timeStamp; // get mousedown time
} else {
diffClick = e.timeStamp - lastClick;
if ( diffClick < clickDelay ) {
// add selected class to group draggable objects
$(this).toggleClass(selectedClass);
}
}
})
.draggable({
revertDuration: 10, // grouped items animate separately, so leave this number low
containment: '.demo',
start: function(e, ui) {
ui.helper.addClass(selectedClass);
},
stop: function(e, ui) {
// reset group positions
$('.' + selectedClass).css({ top:0, left:0 });
},
drag: function(e, ui) {
// set selected group position to main dragged object
// this works because the position is relative to the starting position
$('.' + selectedClass).css({
top : ui.position.top,
left: ui.position.left
});
}
});
$("#droppable, #draggable")
.sortable()
.droppable({
drop: function(e, ui) {
$('.' + selectedClass)
.appendTo($(this))
.add(ui.draggable) // ui.draggable is appended by the script, so add it after
.removeClass(selectedClass)
.css({ top:0, left:0 });
}
});
});
Ответ 2
Рабочее решение
tl; dr: Обратитесь к этому скрипту за рабочий ответ.
Я везде искал решение проблемы перетаскивания нескольких выбранных элементов из сортируемого в связанный сортируемый, и эти ответы были лучшими, что я мог найти.
Однако...
Принятый ответ ошибочен, а @Shanimal answer близок, но не совсем завершен. Я взял код @Shanimal и построил его.
I исправлено:
Я добавил:
- Соответствующая Ctrl + click (или Cmd + click, если на Mac) поддержка для выбора нескольких элементов. Щелчок без удерживаемой клавиши Ctrl приведет к тому, что этот элемент будет выбран, а другие элементы в том же списке будут отменены. Это то же поведение кликов, что и jQuery UI
Selectable()
виджет, разница в том, что Selectable()
имеет выделение на mousedrag.
Fiddle
HTML:
<ul>
<li>One</li>
<li>Two</li>
<li>Three</li>
</ul>
<ul>
<li>Four</li>
<li>Five</li>
<li>Six</li>
</ul>
JavaScript (с jQuery и jQuery UI):
$("ul").on('click', 'li', function (e) {
if (e.ctrlKey || e.metaKey) {
$(this).toggleClass("selected");
} else {
$(this).addClass("selected").siblings().removeClass('selected');
}
}).sortable({
connectWith: "ul",
delay: 150, //Needed to prevent accidental drag when trying to select
revert: 0,
helper: function (e, item) {
var helper = $('<li/>');
if (!item.hasClass('selected')) {
item.addClass('selected').siblings().removeClass('selected');
}
var elements = item.parent().children('.selected').clone();
item.data('multidrag', elements).siblings('.selected').remove();
return helper.append(elements);
},
stop: function (e, info) {
info.item.after(info.item.data('multidrag')).remove();
}
});
Примечание:
Так как я опубликовал это, я реализовал что-то simmilar - подключение перетаскиваемых элементов списка к сортируемым, с возможностью множественного выбора. Он настроен почти точно так же, поскольку виджеты jQuery UI настолько похожи. Один совет UI должен убедиться, что у вас есть параметр delay
для перетаскиваемых или выборочных, поэтому вы можете щелкнуть, чтобы выбрать несколько элементов без инициирования перетаскивания. Затем вы создаете помощника, который выглядит, как и все выделенные элементы (создайте новый элемент, клонируйте выбранные элементы и добавьте их), но убедитесь, что, чтобы оставить оригинальный элемент неповрежденный (в противном случае он закручивает функциональность - я не могу точно сказать, почему, но это связано с множеством разочарований Исключения DOM).
Я также добавил функциональность Shift + Click, так что она больше похожа на собственные настольные приложения. Мне может потребоваться начать блог, чтобы я мог более подробно рассказать об этом: -)
Ответ 3
JSFiddle: http://jsfiddle.net/hQnWG/
<style>
ul {border:1px solid Black;width:200px;height:200px;display:inline-block;vertical-align:top}
li {background-color:Azure;border-bottom:1px dotted Gray}
li.selected {background-color:GoldenRod}
</style>
<h1>Click items to select them</h1>
<ul>
<li>One</li>
<li>Two<li>
<li>Three</li>
</ul><ul>
<li>Four</li>
<li>Five<li>
<li>Six</li>
</ul>
<script>
$("li").click(function(){
$(this).toggleClass("selected");
})
$("ul").sortable({
connectWith: "ul",
start:function(e,info){
// info.item.siblings(".selected").appendTo(info.item);
info.item.siblings(".selected").not(".ui-sortable-placeholder").appendTo(info.item);
},
stop:function(e,info){
info.item.after(info.item.find("li"))
}
})
</script>
Ответ 4
Для этого есть плагин jQuery UI: https://github.com/shvetsgroup/jquery.multisortable
jsFiddle: http://jsfiddle.net/neochief/KWeMM/
$('ul.sortable').multisortable();
Ответ 5
Решение Aaron Blenkush имеет серьезную ошибку: удаление и добавление элементов в структуру сортируемых списков; обновление может помочь, но если другие функции обрабатывают листинг, для обновления требуется триггер для всех, и все это становится чрезмерно сложным.
После анализа некоторых решений в stackoverflow я подвел итоги следующим образом:
Не используйте вспомогательную функцию запуска, потому что у нее уже есть ui.item, которая по умолчанию является помощником.
start: function(event, ui){
// only essential functionality below
// get your own dragged items, which do not include ui.item;
// the example shows my custom select which selects the elements
// with ".selected" class
var dragged = ui.item.siblings(arr["nested_item"]).children('.tRow.tSelected').parent(arr["nested_item"]);
// clone the dragged items
var dragged_cloned = dragged.clone();
// add special class for easier pick-up at update part
dragged_cloned.each(function(){$(this).addClass('drag_clone');});
// record dragged items as data to the ui.item
ui.item.data('dragged', dragged);
// hide dragged from the main list
dragged.hide();
// attached cloned items to the ui.item - which is also ui.helper
dragged_cloned.appendTo(ui.item);
},
-
В части обновления:
update: function(event, ui){
// only essential functionality below
// attach dragged items after the ui.item and show them
ui.item.after(ui.item.data("dragged").show());
// remove cloned items
ui.item.children(".drag_clone").remove();
},
Функция Stop может нуждаться в некоторой копии функциональных возможностей обновления, но, вероятно, будет отделена от обновления, потому что если никаких изменений - ничего не передает серверу.
Добавить: сохранение порядка перетаскиваемых элементов.