2015-11-03 246 views
5

我有以下的情況下,我需要允許用戶從列表中選擇和拖動對象/它們拖放到某個信道:結合AngularJS,jQueryUI的,角拖放的排序列表

enter image description here

對象可以是插槽大小的一至三倍。因此,如果用戶將對象1拖放到插槽0,則它只佔用插槽0(startSlot = 0和endSlot = 0)。但是,如果用戶將對象3拖放到插槽3,則它將佔用插槽3,4和5(startSlot = 3和endSlot = 5)。

將對象放入插槽後,用戶可以通過在插槽中上下拖動對象來重新排序對象。對象不能互相重疊:

enter image description here

我採用了棱角分明,所以我讀從數據庫對象的列表和我有槽的數目的變量。我嘗試了幾個解決方案。我認爲使用jQuery和jQueryUI的可拖動,可棄的,並且排序是解決方案的一部分,這裏是第一小提琴展示拖/下降和排序:

http://jsfiddle.net/mduvall216/6hfuzvws/4/ 

這個小提琴的問題是,我需要一套插槽數量。一旦物體被放置在槽中,取決於物體的大小,它將取代1到3個槽。下面的第二小提琴整合AngularJS:

http://jsfiddle.net/mduvall216/zg5x4b6k/4/ 

這裏的問題是,我知道我需要某種類型的網格捕捉到一次從對象列表中拖動的對象。我正在尋找的結果是其分配的時隙對象的JSON列表:

[{ID:OBJ1,startSlot:0,endSlot:0},{ID:OBJ 3,startSlot:3,endSlot :5}]

我也確信該解決方案將需要位於codf0rmer的角度拖放位置:

https://github.com/codef0rmer/angular-dragdrop 

,但我有去嘗試讓融入了我的小提琴測試問題。這是我一直在旋轉的一個有趣的挑戰,如果任何人都可以得到協助,將不勝感激。謝謝你的時間。

+0

看看https://github.com/angular-ui/ui-sortable,這是流行的AngularUI組件套件的一部分。他們支持連接列表,但是您的物品尺寸要求可能需要一些客戶處理列表項目,但在使用事件時應該直截了當。我以前在項目中成功地使用過它。不幸的是,我現在沒有時間查看您的具體要求。 – Beyers

+0

您也可以使用HTML 5拖放API創建自定義模塊。它很容易實現。 – malinkody

回答

5

我使用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)); 
+0

這很好,正是我需要克服'駝峯'併爲我們的客戶提供解決方案。小提琴是完美的,再次感謝您的幫助。 –