注意:问题的准确描述遵循下面的 CSS。示例代码可见this fiddle 。
我有一个包含子 div 的列表 的父 div,如下所示:
所述容器和子容器的
HTML 是:
<div class="categories_container">
<div class="category one">One</div>
<div class="category two">Two</div>
<div class="category three">Three</div>
<div class="category four">Four</div>
<div class="category five">Five</div>
<div class="category six">Six</div>
</div>
其中类 .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;
}
在 this中可以看出 fiddle,您可以单击(并按住)任何一个子元素并在父 div 中上下移动它。当您释放鼠标时,选定的子项会弹回其原始位置。
问题:
如何检测所选元素是否已被拖动到另一个元素之上?我不仅想知道它们是否重叠,还想在其上设置一个范围。像...
if(center of current child is overtop a set range within another child){
do stuff...
}
我现在想做的(作为概念证明)是让下面的 child 的背景颜色发生变化当所选 child 的垂直中心在 0.4-0.6 范围内时底部 child 的高度。如果选定的 child 被拖出所述区域,背景应该变回。
我试过类似的方法:
$('.category').mouseover(function(){
if(dragging){
... execute code...
}
});
但似乎如果我将一个元素拖到另一个元素上,底部元素就看不到鼠标,因此该函数永远不会执行。
还有:
我尝试了几种不同的方法来在拖动时将光标保持为 pointer
,但无论如何它在拖动时都会切换到文本光标。因此,我们也将不胜感激。
对于指针,我尝试将 $(this).css('cursor', 'pointer');
放在 mousedown
和 mouse 中移动
功能,但无济于事。
提前致谢!抱歉,如果其中任何一个令人困惑。
最佳答案
Here 是我提出的解决方案,完全使用 JS 和 JQuery,不需要外部库,也没有使用 JQueryUI Sortables。
HTML:
<div class="list_container">
<div class="list_item">One</div>
<div class="list_item">Two</div>
<div class="list_item">Three</div>
<div class="list_item">Four</div>
<div class="list_item">Five</div>
<div class="list_item">Six</div>
</div>
其中 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;
}
请访问this fiddle 获取完整的 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
。
$('.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
});
接下来,mousemove
和mouseup
函数绑定(bind)在一起
$(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.
});
最后,getPos
、moveThings
和setNewClass
这三个函数如下:
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]);
}
关于javascript - 使用 JavaScript 通过鼠标拖动来排序图形列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21978551/