使用JavaScript通过鼠标拖动排序图形列表

注意:问题的确切描述遵循以下CSS。 示例代码可以在这个小提琴中看到。

我有一个父div,其中包含一个子div 列表 ,如下所示:

儿童div的列表

所述容器和子容器的HTML是:

One
Two
Three
Four
Five
Six

.one.two.three等等在列表中的相对位置。

子元素在其父元素中以绝对定位定位。

CSS如下( 为简单起见,未显示某些属性 ):

 .categories_container { height: 324px; width: 100%; position: relative; } .category { height: 50px; width: 98%; position: absolute; left: 0px; z-index: 0; } .one { top: 0px; } .two { top: 54px; } .three { top: 108px; } .four { top: 162px; } .five { top: 216px; } .six { top: 270px; } 

这个小提琴中可以看出,您可以单击(并按住)任何一个子元素,并在父div中上下移动它。 释放鼠标时,所选子项将快速回到其原始位置。

题:

如何检测所选元素是否已被拖到另一个元素之上? 我不仅想知道它们是否重叠,而且想在其上加上一个范围。 就像是…

 if(center of current child is overtop a set range within another child){ do stuff... } 

我现在要做的(作为概念certificate)是让所选孩子的垂直中心在底部孩子身高的0.4-0.6范围内,让孩子的背景颜色发生变化。 如果将所选子项拖出所述区域,则背景应更改回来。

我尝试过类似的东西:

 $('.category').mouseover(function(){ if(dragging){ ... execute code... } }); 

但似乎如果我将一个元素拖到另一个元素上,则底部元素无法看到鼠标,因此该函数永远不会执行。

也:

我已经尝试了一些不同的方法来在拖动时将光标保持为pointer ,但无论它在拖动时切换到文本光标是什么。 所以任何帮助也将不胜感激。

对于指针的事情,我试过把$(this).css('cursor', 'pointer');mousedownmouse movefunction,但无济于事。

提前致谢! 很抱歉,如果其中任何一个令人困惑。

是我提出的解决方案,纯粹使用JS和JQuery,不需要外部库,也不使用JQueryUI Sortables。

HTML:

 
One
Two
Three
Four
Five
Six

其中list_container包含各个list_item元素。 它是两者中的后者,可以移动来创建您的排序列表。 你可以在list_item放置任何你想要的东西,它仍然可以正常工作。

CSS:

 .list_container { position: relative; } .list_item { position: absolute; z-index: 0; left: 0px; } .list_item.selected { z-index: 1000; } 

请访问此小提琴以获取CSS规则的完整列表(上面仅显示必需的列表)。

JavaScript的:

我会逐个查看,然后在底部显示完整的代码。

首先,我定义了一个匹配索引号的数组和它们的书面对应物

 var classes = new Array("one", "two", "three", ...); 

这用于动态创建类(在页面加载时)。 这些类用于排序列表。 您只需要使用列表中的项目填充此数组。 这是我编写的代码的一个缺点,我不确定如何克服这个问题(输入数百个项目列表的元素非常繁琐,或者更多!)

接下来,一些其他变量:

 var margin = 2; // Space desired between each list item var $el; // Used to hold the ID of the element that has been selected var oldPos = 0; // The position of the selected element BEFORE animation var newPos = 0; // The position of the selected element AFTER animation (also current position) var dragging = false; // Whether or not an item is being moved var numElements = $('.list_container > div').length; // selectionHeight is the height of each list element (assuming all the same height) // It includes the div height, the height of top and bottom borders, and the desired margin var selectionHeight = $('.list_container .list_item').height() + parseInt($('.list_container .list_item').css("border-bottom-width")) + parseInt($('.list_container .list_item').css("border-top-width")) + margin; var classInfo = ''; // classInfo will be populated with the information that is used to dynamically create classes upon page load 

页面加载时,遍历每个list_item并根据列表中的初始位置为其分配一个类。 还要向classInfo添加列表项TOP的位置。

 $('.list_container .list_item').each(function (index) { $(this).addClass(classes[index]); classInfo += '.' + classes[index] + ' {top: ' + index * selectionHeight + 'px;}\n'; }); 

现在,使用上面创建的classInfo ,动态地将类写入页面。

 var style = document.createElement('style'); style.type = 'text/css'; style.innerHTML = classInfo; document.getElementsByTagName('head')[0].appendChild(style); 

上面的代码将把所需的类写入页面的HTML中。 如果您查看页面的来源,则可以在页面顶部看到这些类。

现在为订购部分。 首先, mousedown

 $('.list_item').mousedown(function (ev) { $el = $(this); oldPos = $el.index() + 1; newPos = oldPos; dragging = true; startY = ev.clientY; // Gets the current mouse position startT = parseInt($el.css('top')); // Gets the current position of the TOP of the item $el.addClass('selected'); // Adding class brings it to top (z-index) and changes color of list item }); 

接下来,将mousemovemouseup函数绑定在一起

 $(window).mousemove(function (ev) { // Use $(window) so mouse can leave parent div and still work if (dragging) { $el.attr('class', 'list_item') // Remove the numbered class (.one, .two, etc) $el.addClass('selected'); // Add this class back for aesthetics // ----- calculate new top var newTop = startT + (ev.clientY - startY); $el.css('cursor', 'pointer'); // ------ //------ stay in parent var maxTop = $el.parent().height() - $el.height(); newTop = newTop < 0 ? 0 : newTop > maxTop ? maxTop : newTop; $el.css('top', newTop); //------ newPos = getPos(newTop, selectionHeight); // Determine what the current position of the selected list item is // If the position of the list item has changed, move the position's current element out of the way and reassign oldPos to newPos if (oldPos != newPos) { moveThings(oldPos, newPos, selectionHeight); oldPos = newPos; } } }).mouseup(function () { dragging = false; // User is no longer dragging $el.removeClass('selected'); // Element is no longer selected setNewClass($el, newPos); // Set the new class of the moved list item $el.css('top', (newPos - 1) * selectionHeight); // Position the moved element where it belongs. Otherwise it'll come to rest where you release it, not in its correct position. }); 

最后, getPosmoveThingssetNewClass三个函数如下:

 function getPos(a, b) { // a == newTop, b == selectionHeight return Math.round( (a/b) + 1 ); } 

getPos工作原理是找出所选元素当前所在的区域。如果newTop小于.5b,则它在区域1中。如果在.5b和1.5b之间,那么它是区域2.如果在1.5b和2.5b之间,然后在3区。依此类推。 在一张纸上写下几个案例,它会发生什么事情。

 function moveThings(a, b, c) { // a == oldPos, b == newPos, c == selectedHeight var first = classes[b - 1]; // What is the current class of the item that will be moved var $newEl = $('.list_container .' + first); // ID of element that will be moved if (a < b) { // oldPos less than newPos var second = classes[b - 2]; // The new class of the moved element will be one less var newTop = parseInt($newEl.css('top')) - c; // Top of element will move up } else { // oldPos more than newPos var second = classes[b]; // The new class of the moved element will be one more var newTop = parseInt($newEl.css('top')) + c; // Top of element will move down } // The following line of code is required, otherwise the following animation // will animate of from top=0px to the new position (opposed to from top=currentPosition) // Try taking it out and seeing $newEl.css('top', parseInt($newEl.css('top'))); $newEl.removeClass(first); // Remove the current numbered class of element to move // Move element and remove the added style tags (or future animations will get buggy) $newEl.animate({top: newTop}, 300, function () { $newEl.removeAttr('style'); }); $newEl.addClass(second); // Add the new numbered class return false; // Cleans up animations } 

上面的函数是实际动画部分和移动列表项以适应所选列表项的内容。

 function setNewClass(e, a) { // e == selected element, a == newPos // Remove 'selected' class, then add back the 'list_item' class and the new numbered class e.attr('class', 'list_item').addClass(classes[a-1]); } 

**所有JavaScript在一起:**

 var classes = new Array("one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeem", "eighteen", "nineteen", "twenty", "twentyone", "twentytwo", "twentythree", "twentyfour"); $(document).ready(function () { var margin = 2; var $el; var oldPos = 0; var newPos = 0; var dragging = false; var selectionHeight = $('.list_container .list_item').height() + parseInt($('.list_container .list_item').css("border-bottom-width")) + parseInt($('.list_container .list_item').css("border-top-width")) + margin; var classInfo = ''; $('.list_container .list_item').each(function (index) { $(this).addClass(classes[index]); classInfo += '.' + classes[index] + ' {top: ' + index * selectionHeight + 'px;}\n'; }); var style = document.createElement('style'); style.type = 'text/css'; style.innerHTML = classInfo; document.getElementsByTagName('head')[0].appendChild(style); $('.list_item').mousedown(function (ev) { $el = $(this); oldPos = $el.index() + 1; newPos = oldPos; dragging = true; startY = ev.clientY; startT = parseInt($el.css('top')); $el.addClass('selected'); }); $(window).mousemove(function (ev) { if (dragging) { $el.attr('class', 'list_item') $el.addClass('selected'); // ----- calculate new top var newTop = startT + (ev.clientY - startY); $el.css('cursor', 'pointer'); // ------ //------ stay in parent var maxTop = $el.parent().height() - $el.height(); newTop = newTop < 0 ? 0 : newTop > maxTop ? maxTop : newTop; $el.css('top', newTop); //------ newPos = getPos(newTop, selectionHeight); if (oldPos != newPos) { moveThings(oldPos, newPos, selectionHeight); oldPos = newPos; } } }).mouseup(function () { dragging = false; $el.removeClass('selected'); setNewClass($el, newPos); $el.css('top', (newPos - 1) * selectionHeight); }); }); function getPos(a, b) { // a == topPos, b == selectionHeight return Math.round((a / b) + 1); } function moveThings(a, b, c) { // a == oldPos, b == newPos, c == selectedHeight var first = classes[b - 1]; var $newEl = $('.list_container .' + first); if (a < b) { // oldPos less than newPos var second = classes[b - 2]; var newTop = parseInt($newEl.css('top')) - c; } else { // oldPos more than newPos var second = classes[b]; var newTop = parseInt($newEl.css('top')) + c; } $newEl.css('top', parseInt($newEl.css('top'))); $newEl.removeClass(first); $newEl.animate({ top: newTop }, 300, function () { $newEl.removeAttr('style'); }); $newEl.addClass(second); return false; // Cleans up animations } function setNewClass(e, a) { // e == selected element, a == newPos e.attr('class', 'list_item').addClass(classes[a - 1]); }