2014-02-24 65 views
1

注意:问题的精确描述如下CSS。示例代码可以在this小提琴中看到。通过使用JavaScript拖动鼠标来订购图形列表

我有一个名单孩子的div内的亲本格,看起来像如下:

List of children divs

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小提琴可以看出,您可以点击(按住)在儿童中的任何一个元素并在父div内上下移动。当您释放鼠标时,选定的孩子会回到原来的位置。

问:

我如何检测所选元素已被拖到顶部之上的另一个?我不仅想知道它们是否重叠,而且想要在其上放置一个范围。喜欢的东西...

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

我想要什么,现在做的(作为概念证明)是有下面的孩子的背景颜色变化WHILE选择孩子的垂直中心距离底部儿童身高的范围在0.4-0.6之间。如果所选的孩子被拖出所述区域,背景应该改回。

我已经试过类似:

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

但似乎如果我拖着一个元素比其他,底部构件不能看到鼠标,所以永远不会执行该功能。

另外:

我已经尝试了几种不同的方法来保持光标作为pointer同时拖动,但不管它切换到文本光标在拖动过程中。所以任何帮助,也将不胜感激。

对于指针的东西,我试过$(this).css('cursor', 'pointer');mousedownmouse move的功能,但无济于事。

在此先感谢!对不起,如果任何这是令人困惑。

+1

jQueryUI的sortables做这样的事情你... – dandavis

+0

所以它。从未听说过它。只要看看[this](https://jqueryui.com/sortable/)链接,你是否知道自己是否能写出它,以便元素没有任何水平自由度?我喜欢他们只能垂直移动,就像我的例子。 – Birrel

+0

是的:http://api.jqueryui.com/sortable/#option-axis – dandavis

回答

3

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捣鼓的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作品通过找出哪个区域选定的元素t当前在。如果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]); 
} 
+0

**编辑** [这](http://jsfiddle.net/gGB4x/9/)小提琴有一个解决方案,它没有类数组,并将工作任何长度的列表。使用我写的'toNumber()'函数。它并没有真正写出数字(即22是两个),但每个类别都是唯一的,这就是所需要的。 – Birrel

+0

**编辑#2 ** ...上次我添加到此答案... ** [这](http://jsfiddle.net/gGB4x/14/)**解决方案修复了动画问题,并且工作*完美*(就我而言)!几个变化:1)现在在CSS中更改页边距,2)父div高度自动设置,3)将'.stop()'添加到动画中,现在事情效果更好,4)更改了'toNumer()'类的名称从以前的评论到'numToClass()'以避免混淆。 – Birrel

+1

不错的解决方案,并写下来! – dandavis

相关问题