我使用HTML5 Drag & Drop API和jQuery開始了您的需求的基本實現。該API輕量級,不需要任何第三方腳本。代碼應該很容易定製。提供的示例僅僅是一個起點,決不是生產準備就緒,應該優化,並可能在使用前變爲jQuery插件模塊。這會增加模塊的可重用性。
在評論中留下任何關於代碼的進一步問題。
JSFiddle Example without sortable:
JSFiddle with sortable
HTML:
<ul class="select-list">
<li class="header">Object List</li>
<li data-slots="1" class="s1">Object 1</li>
<li data-slots="2" class="s2">Object 2</li>
<li data-slots="3" class="s3">Object 3</li>
</ul>
<ul class="drop-list" id="sortable">
<li>Slot 1</li>
<li>Slot 2</li>
<li>Slot 3</li>
<li>Slot 4</li>
<li>Slot 5</li>
<li>Slot 6</li>
<li>Slot 7</li>
<li>Slot 8</li>
<li>Slot 9</li>
<li>Slot 10</li>
<li>Slot 11</li>
<li>Slot 12</li>
<li>Slot 13</li>
</ul>
的JavaScript沒有排序:
(function ($, undefined) {
// document ready function
$(function() {
init();
$('ul.select-list').on({
'dragstart': dragstart,
'dragend': dragend
}, 'li');
$('ul.drop-list').on({
'dragenter dragover': dragover,
'dragleave': dragleave,
'drop': drop
}, 'li.dropzone');
});
// Initializes the lists
function init() {
$('ul.select-list').find('li').not('[class="header"]').each(function() {
var height = getSlotHeight() * $(this).data('slots');
$(this).height(height);
}).attr('draggable', true);
$('ul.drop-list').find('li').each(function() {
$(this).height(getSlotHeight());
}).addClass('dropzone');
}
// Get the height of grid slots
function getSlotHeight() {
return 20;
}
/**
* Checks whether target is a kompatible dropzone
* A dropzone needs the dropzone class
* and needs to have enough consequent slots to drop the object into
*/
function isDropZone(target, draggedObj) {
var isDropZone = true;
var slots = draggedObj.data('slots');
for (var i = 1; i < slots; i++) {
target = target.next();
if (target.size() == 0 || !target.hasClass('dropzone')) {
isDropZone = false;
break;
}
}
return isDropZone;
}
/*
* The following events are executed in the order the handlers are declared
* dragstart being first and dragend being last
*/
// dragstart event handler
function dragstart(e) {
e.stopPropagation();
var dt = e.originalEvent.dataTransfer;
dt.effectAllowed = 'move';
dt.setData('text/html', '');
$('ul.select-list').data({
draggedObj: $(this)
});
}
// dragover event handler
function dragover(e) {
e.preventDefault();
e.stopPropagation();
var data = $('ul.select-list').data();
if (!data.draggedObj || !isDropZone($(this), data.draggedObj)) {
e.originalEvent.dataTransfer.dropEffect = 'none';
return;
}
e.originalEvent.dataTransfer.dropEffect = 'move';
var item = $(this).addClass('dragover');
var slots = data.draggedObj.data('slots');
for (var i = 1; i < slots; i++) {
item = item.next('li').addClass('dragover');
}
return false;
}
// dragleave event handler
function dragleave(e) {
e.preventDefault();
e.stopPropagation();
var data = $('ul.select-list').data();
if (!data.draggedObj || !isDropZone($(this), data.draggedObj)) {
return;
}
var item = $(this).removeClass('dragover');
var slots = data.draggedObj.data('slots');
for (var i = 1; i < slots; i++) {
item = item.next('li').removeClass('dragover');
}
return false;
}
// drop event handler
function drop(e) {
e.stopPropagation();
e.preventDefault();
var data = $('ul.select-list').data();
if (data.draggedObj || !isDropZone($(this), data.draggedObj)) {
data.target = $(this);
data.draggedObj.trigger('dragend');
}
return false;
}
// dragend event handler
function dragend(e) {
var data = $('ul.select-list').data();
if (data.draggedObj && data.target && isDropZone(data.target, data.draggedObj)) {
var item = data.target.hide();
var slots = data.draggedObj.data('slots');
for (var i = 1; i < slots; i++) {
item = item.next('li').hide();
}
data.target.before(data.draggedObj);
}
data.target = undefined;
data.draggedObj = undefined;
$('ul.drop-list').find('li').removeClass('dragover');
}
}(jQuery));
CSS:
ul {
list-style-type: none;
margin: 0;
padding: 0;
float: left;
}
li {
width: 150px;
}
li.header {
height:20px;
font-weight:bold;
}
.select-list li {
margin-bottom: 10px;
}
.drop-list {
margin-left:20px;
}
.drop-list li {
background-color: #ccc;
border-left: 1px solid black;
border-right: 1px solid black;
border-top: 1px solid black;
}
.drop-list li.dragover {
background-color:#fff;
}
.drop-list li:last-child {
border-bottom: 1px solid black;
}
li.s1 {
background-color: #FFE5E5;
}
li.s2 {
background-color: #C6D4FF;
}
li.s3 {
background-color: #C6FFE3;
}
編輯:以下腳本也將排序添加到它。我沒有壓力測試這個例子,它可能不會在某些條件下執行。
(function ($, undefined) {
// document ready function
$(function() {
init();
$('ul.select-list,ul.drop-list').on({
'dragstart': dragstart,
'dragend': dragend
}, 'li.object').on('dragenter dragover', listDragover);
$('ul.drop-list').on({
'dragenter dragover': dragover,
'dragleave': dragleave,
'drop': drop
}, 'li.dropzone');
});
// Initializes the lists
function init() {
$('ul.select-list').find('li').not('[class="header"]').each(function() {
var height = getSlotHeight() * $(this).data('slots');
$(this).height(height);
}).attr('draggable', true).addClass('object');
$('ul.drop-list').find('li').each(function() {
$(this).height(getSlotHeight());
}).addClass('dropzone');
}
// Get the height of the grid
function getSlotHeight() {
return 20;
}
/**
* Checks whether target is a kompatible dropzone
* A dropzone needs the dropzone class
* and needs to have enough consequent slots to drop the object into
*/
function isDropZone(target, draggedObj) {
var isDropZone = true;
var slots = draggedObj.data('slots');
for (var i = 1; i < slots; i++) {
target = target.next('li');
if (target.size() == 0 || !target.hasClass('dropzone')) {
if (!target.is(draggedObj)) {
isDropZone = false;
break;
} else {
i--;
}
}
}
return isDropZone;
}
// dragstart event handler
function dragstart(e) {
e.stopPropagation();
var dt = e.originalEvent.dataTransfer;
dt.effectAllowed = 'move';
dt.setData('text/html', '');
$('ul.select-list').data({
draggedObj: $(this)
});
}
// dragover list event handler
function listDragover(e) {
e.preventDefault();
e.stopPropagation();
e.originalEvent.dataTransfer.dropEffect = 'none';
var data = $('ul.select-list').data();
if (data.draggedObj) {
var item = data.draggedObj;
item.hide();
if (data.draggedObj.closest('ul').is('ul.drop-list')) {
var slots = item.data('slots');
for (var i = 0; i < slots; i++) {
item = item.next('li').show();
}
}
}
return false;
}
// dragover event handler
function dragover(e) {
e.preventDefault();
e.stopPropagation();
var data = $('ul.select-list').data();
if (!data.draggedObj || !isDropZone($(this), data.draggedObj)) {
e.originalEvent.dataTransfer.dropEffect = 'none';
return;
}
e.originalEvent.dataTransfer.dropEffect = 'move';
var item = $(this).addClass('dragover');
var slots = data.draggedObj.data('slots');
for (var i = 1; i < slots; i++) {
item = item.next('li');
if (!item.is(data.draggedObj)) {
item.addClass('dragover');
} else {
i--;
}
}
return false;
}
// dragleave event handler
function dragleave(e) {
e.preventDefault();
e.stopPropagation();
var data = $('ul.select-list').data();
if (!data.draggedObj || !isDropZone($(this), data.draggedObj)) {
return;
}
var item = $(this).removeClass('dragover');
var slots = data.draggedObj.data('slots');
for (var i = 1; i < slots; i++) {
item = item.next('li');
if (!item.is(data.draggedObj)) {
item.removeClass('dragover');
} else {
i--;
}
}
return false;
}
// drop event handler
function drop(e) {
e.stopPropagation();
e.preventDefault();
var data = $('ul.select-list').data();
if (data.draggedObj || !isDropZone($(this), data.draggedObj)) {
data.target = $(this);
data.draggedObj.trigger('dragend');
}
return false;
}
// dragend event handler
function dragend(e) {
var data = $('ul.select-list').data();
var target = data.target;
if (data.draggedObj && !target && data.draggedObj.closest('ul').is('ul.drop-list')) {
target = data.draggedObj.next('li');
}
if (data.draggedObj && target && isDropZone(target, data.draggedObj)) {
data.draggedObj = data.draggedObj.insertBefore(target);
var item = target.hide();
var slots = data.draggedObj.data('slots');
for (var i = 1; i < slots; i++) {
item = item.next('li').hide();
}
}
if (data.draggedObj) {
data.draggedObj.show();
}
data.target = undefined;
data.draggedObj = undefined;
$('ul.drop-list').find('li').removeClass('dragover');
}
}(jQuery));
看看https://github.com/angular-ui/ui-sortable,這是流行的AngularUI組件套件的一部分。他們支持連接列表,但是您的物品尺寸要求可能需要一些客戶處理列表項目,但在使用事件時應該直截了當。我以前在項目中成功地使用過它。不幸的是,我現在沒有時間查看您的具體要求。 – Beyers
您也可以使用HTML 5拖放API創建自定義模塊。它很容易實現。 – malinkody