2010-06-22 230 views
3

請參閱代碼here on jsbin.我基本上試圖創建一系列開關。每個填充的紅色方塊都可以上下拖動。底部的紅色輪廓是放置區域。當一個正方形被拖過一個有資格接受它的放置區時,放置區應該變成粉紅色。jQuery拖/放範圍問題

這個代碼有兩個問題。其中之一是,雖然觸發器的運動被限制在y軸上,但它們仍然可以落在任何放置區域上。點擊並拖動切換按鈕並滑動底部行,即使切換保持原位,您也會看到拖放區變成粉紅色。

這導致第二個問題。爲了解決這個問題,我嘗試使用範圍選項,該選項將拖放組合起來。拖動只能放在具有相同範圍的拖放區域上。在上面的例子中,添加範圍的行被註釋掉了。每個拖放的範圍都是「默認」。

如果您取消註釋這兩行(如果您是jsbin的新手,請單擊右上角的標籤,然後在更改後單擊預覽),您會看到,不是將每個拖動限制到一個拖放區域,而是可以不再落在任何拖放區域。回調函數永遠不會觸發。

爲了方便起見,這裏是實施例的一部分的javascript:

$(document).ready(function() { 
    var draggables = $('div.dragMe'), 
    droppables = $('div.dropMe'); 

    draggables.draggable(
    { 
     axis: 'y', 
     containment: 'parent' 
    }); 

    droppables.droppable(
    { 
     hoverClass: 'dropped', 
     drop: dropCallBack 
    }); 

    draggables.each(function(index) { 
     //$(this).draggable('option', 'scope', ''+index); 
     //droppables.eq(index).droppable('option', 'scope', ''+index); 

     $(this).text($(this).draggable('option', 'scope')) 
     droppables.eq(index).text(droppables.eq(index).droppable('option', 'scope')); 
    }); 

    function dropCallBack(e, ui) { 
     alert('Dropped!'); 
    } 
}); 
+0

我不想給防解決方案,但你有沒有考慮,而不是拖放,只是觸發與開關mouseDown'.mousedown(function)'事件?在我看來,它的可用性更好(作爲最小wtf的路徑),並與移動設備相處得更好。 – 2010-06-22 21:40:11

+0

有時反解決方案是最好的解決方案!好點子。如果我得到這個工作,我總是可以做到這一點。最初的想法是嘗試設計一些使用物理類比進行交互的導航元素。當它們被釋放時,開關應當「卡扣」到位,就好像有一個制動器,只是還沒有寫入那個零件。 – jasongetsdown 2010-06-22 21:59:07

回答

9

經由選項功能設置一個可投放的scope選項時有jQuery中的一個錯誤。 jQuery維護一個包含所有已註冊排序的數組(現在讓我們稱它爲S),其中每個鍵都是一個特定的作用域。將可拖動元素拖放到可拖放元素中時,jQuery將檢查可拖動元素的範圍屬性,並檢查您嘗試拖動的拖放元素是否存在於S[scope]中。如果不是,則意味着您要拖入的拖放與拖動不在同一範圍內。

問題是,當您通過執行.droppable('option', 'scope', ...)更改範圍選項時,數組S未更新。其他所有內容(就我所見)已正確更新(實際jQuery對象的選項屬性等),導致在通過.droppable('option', 'scope')獲取範圍選項時返回「正確」結果。

我發現了一些其他人有相同的問題,沒有解決方案出現了,這個問題出現了,當我搜索解決方案("jquery droppable scope option"),所以我認爲它可能是有用的,直到它提供一個臨時解決方案是固定的。我做了一個擴展功能,對於可能與其他選項的衝突沒有很好的測試,但至少這是一個開始。 $.ui.ddmanager.droppables是我以前稱爲S的數組。

jQuery.fn.extend({ 

    setDroppableScope: function(scope) { 
     return this.each(function() { 
      var currentScope = $(this).droppable("option","scope"); 
      if (typeof currentScope == "object" && currentScope[0] == this) return true; //continue if this is not droppable 

      //Remove from current scope and add to new scope 
      var i, droppableArrayObject; 
      for(i = 0; i < $.ui.ddmanager.droppables[currentScope].length; i++) { 
       var ui_element = $.ui.ddmanager.droppables[currentScope][i].element[0]; 

       if (this == ui_element) { 
        //Remove from old scope position in jQuery's internal array 
        droppableArrayObject = $.ui.ddmanager.droppables[currentScope].splice(i,1)[0]; 
        //Add to new scope 
        $.ui.ddmanager.droppables[scope] = $.ui.ddmanager.droppables[scope] || []; 
        $.ui.ddmanager.droppables[scope].push(droppableArrayObject); 
        //Update the original way via jQuery 
        $(this).droppable("option","scope",scope); 
        break; 
       } 
      } 
     }); 
    } 
}); 

你的例子,然後像

draggables.each(function(index) { 
    $(this).draggable('option', 'scope', ''+index); 
    droppables.eq(index).setDroppableScope(''+index); 

    $(this).text($(this).draggable('option', 'scope')) 
    droppables.eq(index).text(droppables.eq(index).droppable('option', 'scope')); 
}); 

Here's the updated jsbin

+1

平反!表現完全如預期。感謝您深入瞭解一個狡猾的錯誤,並提供代碼來修復它。正如你所說,它報告了正確的範圍,但後來就表示不在乎! – jasongetsdown 2010-06-23 14:14:03

+0

這是2013年,這個錯誤仍然存​​在:( – pckben 2013-08-29 19:00:00