1. 程式人生 > >easyUI拖拽功能講解以及多選拖拽的實現

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");
					});
				}
			}
		});

對於拖到維修組中放開滑鼠後的處理也要分開討論了,這個也比較好理解~

那就寫到這裡~下班回家!