easyUI拖拽功能講解以及多選拖拽的實現
首先我們考慮這樣一個業務場景:一個維修部門中分了N個維修組,維修部門的負責人需要將這個部門的維修人員分配到這些組裡去。
當然,他可以選中一個維修人員,然後給他分配維修組,但是從人性化角度考慮,若利用拖拽是否更加的快捷和明確呢?
比如我們可以將維修組和維修人員都列出來,然後只需要將維修人員拖動到對應的組裡即可完成分組。
另外,由於一個個拖還是太繁瑣,還需要實現選中多個維修人員一起分組。那麼我們下面一步步來,先實現單個的拖拽功能,再加入多選拖動支援~
單選拖動
首先,根據我們剛才描述的場景,簡單設計一個佈局:
接下來,我們需要做的是:
1、讓維修人員對應的小方塊可以拖動起來
這就需要把每個小方塊都註冊成draggable(這裡我為每個小方塊添加了class='employee'方便選擇)
$('.employee').draggable( { revert : true, proxy : 'clone', onStartDrag : function() { $(this).draggable('options').cursor = 'not-allowed'; $(this).draggable('proxy').css('z-index', 10); $(this).draggable('proxy').addClass('dp') }, onStopDrag : function() { $(this).draggable('options').cursor = 'move'; } });
關於draggable中的屬性設定,這裡也講解一下:
revert:true表示當停止拖動後,小方塊迴歸原位(false則不迴歸)
proxy:'clone'表示拖動的那個元素,如果設定成clone,那麼它會自動幫你clone一個元素用來給你拖動,如果要自己寫的話,返回的必須是一個jQuery物件。這個在後面多選拖動的實現中會講到。
onStartDrag 開始拖動時會觸發,可以看到這裡我們設定了一些視覺上的效果,比如新增一個不可防止的這麼一個小角標,並且透明度變低(.dp)
onStopDrag 結束拖動時觸發,還原角標
2、讓小方塊可以放置到上面的組裡,並顯示出來
那麼首先需要把上面的組註冊成droppable(這裡為組的上一層ul添加了.group-list方便選擇)
$('.group-list li').droppable( { // 注意,這裡要用li,不能直接用 .easyui-datagrid
onDragEnter : function(e, source) {
$(source).draggable('options').cursor = 'auto';
},
onDragLeave : function(e, source) {
$(source).draggable('options').cursor = 'not-allowed';
},
onDrop : function(e, source) {
var empno = $(source).find('p:eq(0)').html();
var name = $(source).find('p:eq(1)').html();
var phone = $(source).find('p:eq(2)').html();
addEmployee(empno.split(':')[1], name.split(':')[1],
phone.split(':')[1], $(this).find('[id^=group]'));
$(source).parent().hide();
}
});
這裡幾個事件都比較好理解,看名字就可以了
onDragEnter: 當拖動的小方塊進入時觸發
onDragLeave: 當拖動的小方塊離開時觸發
onDrop: 當拖動的小方塊進入後並放開滑鼠時觸發
當然,onDrop顯然是最重要的,放開滑鼠後我們需要將小方塊代表的維修人員新增到對應的組中,也就是addEmployee(...)這個函式
function addEmployee(empno, name, phone, dg) {
var data = dg.datagrid('getData');
function add() {
data.total += 1;
data.rows.push( {
empno : empno,
name : name,
phone : phone
});
}
add();
dg.datagrid('loadData', data);
}
這裡的dg是通過小方塊拖動放開的組來找到的,也就是onDrap函式中$(this).find('[id^=group]')來找的。這裡有個小技巧,就是將組的id都命名成group開頭,後面加一個組的編號,這主要是由於easyUI對非id訪問元素的支援不是很好。
至此,單選拖拽就講完了,你可以試試拖動小方塊到維修組裡試試~
多選拖動
下面開始講解多選拖動,多選拖動的難點在於,如何選?最完美的方式當然是單擊小方塊後選中,然後一起拖到維修組中。
但是,單擊小方塊也會被認為是 拖動 而觸發onDrapStart,而並不會觸發onClick事件。
那麼是否可以在小方塊中新增一個多選框(checkbox)而不觸發拖動事件?
我實踐後發現由於在拖動時會clone出一個小方塊並且覆蓋在之前的小方塊上,所以基本上點不到原來的小方塊(快速點選倒是會成功,但是顯然這種方案也不行)
而我之前做這個的時候用了一種方法,是利用了draggable的deltaX和deltaY兩個屬性,這兩個屬性的意思是clone出來的一個小方塊相對於原來的小方塊的位置
這樣的話只要避免遮蓋到checkbox就可以多選了!但是由於單擊的時候會跳一下,這裡並不推薦,有興趣的朋友可以試試。
另外一種方法,就是將可拖動的小方塊和多選框分開,這樣一來就不會被遮擋了(為什麼之前沒想到),下面就直接上程式碼了,大家可以和之前單選的對比著看
$('.employee').draggable( {
revert : true,
proxy : function(source){
if($(":checkbox:checked").length == 0){
var clone = $(source).clone();
clone.insertBefore($(source));
return clone;
}else{
var div = $("<div/>");
$(":checkbox:checked").each(function(){
var clone = $(this).prev().clone();
div.append(clone);
});
div.insertBefore($(source));
return div;
}
},
onStartDrag : function() {
$(this).draggable('options').cursor = 'not-allowed';
$(this).draggable('proxy').css('z-index', 10);
$(this).draggable('proxy').addClass('dp')
},
onStopDrag : function() {
$(this).draggable('options').cursor = 'move';
}
});
我這裡將選中checkbox多選的和沒選checkbox單選的這兩種情況分開,這裡唯一不一樣的就是proxy屬性
關於這個proxy其實就是在介面上clone一個代理小方塊出來,用來拖動顯示用,那麼對於多選來說,我們首先需要克隆出選中的小方塊,然後將小方塊塞到介面中,然後需要將這些小方塊返回給proxy。這裡還有個問題就是,我嘗試了很多次,只能返回jQuery物件,且不能是jQuery陣列。所以只能搞個div然後把選中的小方塊都塞到這個div裡,最後會有一個一起拖著走的效果,當然這純粹是為了效果好,用之前的proxy:'clone'也可以達到多選拖動的目的,只不過在拖動過程中的顯示上只會出現最後拖動的那個小方塊。
$('.group-list li').droppable( { // 注意,這裡要用li,不能直接用 .easyui-datagrid
onDragEnter : function(e, source) {
$(source).draggable('options').cursor = 'auto';
},
onDragLeave : function(e, source) {
$(source).draggable('options').cursor = 'not-allowed';
},
onDrop : function(e, source) {
if($(":checkbox:checked").length == 0){
var empno = $(source).find('p:eq(0)').html();
var name = $(source).find('p:eq(1)').html();
var phone = $(source).find('p:eq(2)').html();
addEmployee(empno.split(':')[1], name.split(':')[1],
phone.split(':')[1], $(this)
.find('[id^=group]'));
$(source).parent().hide();
}else{
var li = $(this); // 防止each裡訪問不到this
var group = li.find('[id^=group]');
$(":checkbox:checked").each(function(){
var empno = $(this).prev().find('p:eq(0)').html();
var name = $(this).prev().find('p:eq(1)').html();
var phone = $(this).prev().find('p:eq(2)').html();
addEmployee(empno.split(':')[1], name.split(':')[1],
phone.split(':')[1], group);
$(this).parent().hide();
$(this).removeAttr("checked");
});
}
}
});
對於拖到維修組中放開滑鼠後的處理也要分開討論了,這個也比較好理解~
那就寫到這裡~下班回家!