2014-02-24 72 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

相關問題