DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> JavaScript入門知識 >> JavaScript基礎知識 >> javascript小實例,PC網頁裡的拖拽
javascript小實例,PC網頁裡的拖拽
編輯:JavaScript基礎知識     

幾年前,我參與設計開發一個房產網的項目,我負責前端工作,由於項目經理要求比較高,參考了很多房產類網站比較優秀的功能,想把別人比較優秀的設計和想法集合到一起,那時的設計稿和功能實現,簡直就是改了又改,今天做好的一個很好的效果,可能第二天就要推到重來,算了,不說這些了,還是說說我們今天要講解的案例吧,不知道大家訪問過搜房網沒有(完全沒有做廣告之嫌,搜房網,可以給點廣告費不),其中有一個功能產品經理特別喜歡,那,就是下面的這個:

這是現在的效果,可能改了一些,原來的效果是,裡面的這張圖是可以上下左右拖動的,然後房子上面的顯示的樓棟號,也跟著圖片一起移動,當時js能力還不行,未能實現項目經理的要求,不過後來項目經理又把這個效果推掉了,換了另外的一個效果

盡管項目經理不想要這個效果了,但是當時就在我心裡留下了一個節,到今天都忘不了這個梗。

好了,這就是我今天想寫這篇博客的初衷,希望能給想實現這類拖拽效果,但是不知道該怎麼去實現的同學,提供一種思路,不給青春留遺憾,當然實現拖拽的方法有很多,這裡就只介紹JavaScript中的一種方法,慢慢體會一下其中的原理!

好了,梗也說完了,開始正題,我們先要明白,拖拽到底是一個什麼東西,你也知道,我也知道,但是我還是想來描述一下:

拖拽就是一個容器,你用鼠標可以在頁面上拖著到處跑,廢話,精確的描述應該是,鼠標移到容器上,然後鼠標按下去,注意要按著不放,然後拖動鼠標,容器能跟著鼠標跑,松開鼠標,容器就停在那裡不動了,現實中的例子就是桌子上有一個盒子,我用手放在盒子上,然後移動盒子,手停盒子停,手拿開,盒子不動了,嘻嘻,都懂了哈!

別以為上面說了一堆的廢話,我們可以從中得到很多的信息,總結如下就是:

拖拽 = 鼠標按下 + 鼠標移動 + 鼠標彈上

這樣就完成了一個拖拽任務,好了,原來這就是拖拽的原理,想實現拖拽,自然實現上面的3個動作,便可以模擬拖拽效果,好,對應JavaScript中的語法就是需要實現這3個動作:

onmousedown , onmousemove , onmouseup

 實現的代碼就應該是:

obj.onmousedown = function(ev){
      obj.onmousemove = function(ev){ 

      } ;
      obj.onmouseup = function(ev){
     
      };
    
}

為什麼後面2個動作要寫的裡面,好好回味一下,好了,第一步的大概思路就有了,下一步就需要考慮怎麼讓物體跟著鼠標一起移動,思路大概是這樣的:

首先物體是需要決定定位的,因為我們需要操作它的left和top值,才能讓它移動,然後就是要考慮鼠標了,鼠標位移,本身就會有一個距離,如果我們知道鼠標移動了多遠,然後把這個距離給物體,那物體是不是也和鼠標一樣,移動了相同的距離,這不就實現拖拽了嗎?哈哈,思路一點點有,感覺萌萌哒~ 現在的問題就是怎麼獲取鼠標的距離,如果需要深入了解,請復習一下盒子模型,這裡我就不說了,很多大神也有相關的博客,我用一張圖表示一下:

說明:藍色框為屏幕寬高,黑色粗框為浏覽器可視區寬高(浏覽器縮小效果),黑色細框為鼠標要拖拽的對象,如圖可知,獲取鼠標的坐標,可以用event.clientX,event.clientY來獲取,哦了;

計算的大致原理可以參照下圖:

說明:左邊為初始位置,右邊為目標位置,原點為鼠標位置,大黑框為浏覽器可視寬度,小黑框為拖拽對象,看拖拽對象到目標位置的狀態,獲取鼠標的最終位置,再減去鼠標距離對象的差值,再賦值給對象的top,left值,也可以獲取鼠標的位置差值,再用初始的top,left值加上差值,我們采用第一種,第二種也可以,自己去試一下:

 

obj.onmousedown = function(ev){
	var ev = ev || event;
	var disX = ev.clientX - this.offsetLeft,disY = ev.clientY - this.offsetTop;

	document.onmousemove = function(ev){
		var ev = ev || event;
		obj.style.left = ev.clientX - disX + 'px';
		obj.style.top = ev.clientY - disY + 'px';
	};
	document.onmouseup = function(ev){
		var ev = ev || event;
		document.onmousemove = document.onmouseup = null;
	};
}

這裡說明一下:onmousemove和onmouseup之所以用document對象而不用obj對象,是因為如果用obj對象,鼠標在obj內部還好,如果在obj外面的話,拖拽會很怪異,你也可以改成obj體會一下,最後我們在鼠標彈起的時候將事件都清空;

上面的基本拖拽就算完成了,但是細心的同學一定會問,如果頁面上有文字的話,拖拽物體會將文字選中,這效果豈不是怪怪的,沒錯,這是因為拖拽的時候觸發了浏覽器的默認選擇事件,所以,在拖拽的時候,我們要清除這個默認事件,那怎麼清除呢?

下面給一個兼容性寫法:

if(ev.stopPropagation){
     ev.stopPropagation();
}else{
    ev.cancelBubble = true; //兼容IE
}
//簡寫成
ev.stopPropagation ? ev.stopPropagation() : ev.cancelBubble = true;

將上面的代碼放在onmousedown下,鼠標按下就清除浏覽器默認事件,文字就不會被選中了,好了,一個簡單的拖拽效果就完成了,當然你現在是看不到效果,之所以不給demo鏈接是為了讓你自己試著寫一寫,這樣印象更深刻,

好了,那問題又來了,到這裡就這樣完了嗎?。。。。。。按本人的風格,當然沒有,干貨還在後面!

如果我想實現這樣一個效果,就是這一個大的容器裡面(可以是box,也可以是document),怎麼樣能讓我們的拖拽對象不跑出去呢,換句話說,拖到邊緣就拖不動了,耶,是不是很多人想要實現的效果,哈哈,我們看看實現的原理是什麼:

現實生活中,一個物體在一個盒子裡跑不出去,是因為有堵牆,那我們只要能模擬出這堵牆,就可以把物體框起來,那這堵牆要怎麼做呢?我們可以換個思路,當拖拽對象拖到邊緣的時候,比如說拖到右邊,我們將它的left固定住,是不是就不能再往右了,因為left值不能再加了,那麼拖到底部,同理我們將top值固定住,就不能再往下拖了,理解嗎?

最終的結果就是如下:

//左側
if(obj.offsetLeft <=0){
	obj.style.left = 0;	
};
//右側
if(obj.offsetLeft >= pWidth - oWidth){
	obj.style.left =  pWidth - oWidth + 'px';	
};
//上面
if(obj.offsetTop <= 0){
    obj.style.top = 0;	
};
//下面
if(obj.offsetTop >= pHeight - oHeight){
    obj.style.top =  pHeight - oHeight + 'px';	
};

說明:pWidth,pHeight 表示父級元素的寬高(這裡是表示相對於父級的寬高限制),oWidth,oHeigt表示拖拽元素的寬高

最後,我將整個拖拽代碼整理了一下:

/*
			參數說明:
			元素絕對定位,父級相對定位,如果父級為window,則可以不用
			傳一個參數,表示父級為window,物體相對於window范圍拖動
			傳2個參數,則父級為第二個參數,物體相對於父級范圍拖動
			參數為id值
		*/
		function drag(obj,parentNode){
			var obj = document.getElementById(obj);
			if(arguments.length == 1){
				var parentNode = window.self;	
				var pWidth = parentNode.innerWidth,pHeight = parentNode.innerHeight;	
			}else{
				var parentNode = document.getElementById(parentNode);
				var pWidth = parentNode.offsetWidth,pHeight = parentNode.offsetHeight;
			}
			obj.onmousedown = function(ev){
				var ev = ev || event;
				var disX = ev.clientX - this.offsetLeft,disY = ev.clientY - this.offsetTop;
				var oWidth = obj.offsetWidth,oHeight = obj.offsetHeight;
				
				//阻止冒泡時間
				ev.stopPropagation ? ev.stopPropagation() : ev.cancelBubble = true;
			
				
				document.onmousemove = function(ev){
					var ev = ev || event;
					obj.style.left = ev.clientX - disX + 'px';
					obj.style.top = ev.clientY - disY + 'px';
					
					//左側
					if(obj.offsetLeft <=0){
						obj.style.left = 0;	
					};
					//右側
					if(obj.offsetLeft >= pWidth - oWidth){
						obj.style.left =  pWidth - oWidth + 'px';	
					};
					//上面
					if(obj.offsetTop <= 0){
						obj.style.top = 0;	
					};
					//下面
					if(obj.offsetTop >= pHeight - oHeight){
						obj.style.top =  pHeight - oHeight + 'px';	
					};
				};
				document.onmouseup = function(ev){
					var ev = ev || event;
					document.onmousemove = document.onmouseup = null;
				};
			}
				
		}

說明:我這裡處理的效果是,如果傳一個參數,表示相對的對象是window對象,如果傳2個參數,第一個是拖拽對象,第二個為相對父級

開篇就說了,搜房網的那個圖片拖拽效果是我的一個心結,我寫了一個類似的效果,供大家參考,因為自己沒有買服務器,所以效果我就不展示了,直接把代碼貼出來,供大家參考:

css:

<style>
.box{
	width:600px;
	height:400px;
	margin:50px auto;
	position:relative;
	overflow:hidden;
}
#box{
	width:1000px;
	height:800px;
	position:absolute;
	left:50%;
	top:50%;
	margin:-400px 0 0 -500px;
}
#pic{ width:800px; height:600px; background:url(images/pic1.jpg) no-repeat; position:absolute; left:100px; top:100px; }
#pic:hover{
	cursor:move;
}
</style>

html:

<div class="box">
    	<div id="box">
        	<div id="pic"></div>
        </div>
    </div>

javascript:

window.onload = function(){
		
		drag("pic","box");
		function drag(obj,parentNode){
			var obj = document.getElementById(obj);
			if(arguments.length == 1){
				var parentNode = window.self;	
				var pWidth = parentNode.innerWidth,pHeight = parentNode.innerHeight;	
			}else{
				var parentNode = document.getElementById(parentNode);
				var pWidth = parentNode.offsetWidth,pHeight = parentNode.offsetHeight;
			}
			obj.onmousedown = function(ev){
				var ev = ev || event;
				var disX = ev.clientX - this.offsetLeft,disY = ev.clientY - this.offsetTop;
				var oWidth = obj.offsetWidth,oHeight = obj.offsetHeight;
				
				//阻止冒泡時間
				ev.stopPropagation ? ev.stopPropagation() : ev.cancelBubble = true;
			
				
				document.onmousemove = function(ev){
					var ev = ev || event;
					obj.style.left = ev.clientX - disX + 'px';
					obj.style.top = ev.clientY - disY + 'px';
					
					//左側
					if(obj.offsetLeft <=0){
						obj.style.left = 0;	
					};
					//右側
					if(obj.offsetLeft >= pWidth - oWidth){
						obj.style.left =  pWidth - oWidth + 'px';	
					};
					//上面
					if(obj.offsetTop <= 0){
						obj.style.top = 0;	
					};
					//下面
					if(obj.offsetTop >= pHeight - oHeight){
						obj.style.top =  pHeight - oHeight + 'px';	
					};
				};
				document.onmouseup = function(ev){
					var ev = ev || event;
					document.onmousemove = document.onmouseup = null;
				};
			}
				
		}
		
		
	}

效果完全是用的那個封裝代碼塊,引用起來也挺方便,有人會問了,你這用的id獲取DOM元素,一個頁面只能用一次啊,如果頁面多次使用呢,有道理,解決方案之一,那就命名不同的id呗,又不犯法,方案二,獲取id的地方改成獲取class,但是要注意的是,getElementsByClassName是獲取的class集合,需要改寫一下,這裡我就不寫了,有興趣的同學自行改寫一下,好了,到這裡真的結束了!

下期預告:

突然想到了一個梗(宋丹丹老師的,寫完《月子1》就想寫《月子2》),既然知道PC怎麼實現拖拽,那移動端怎麼實現呢?那我就想寫完PC就想寫移動端的,那我准備准備,下期見!

哈哈,我也被雷到了,居然還搞個下期預告,純屬心血來潮,實現方法有很多,我的目的只是想幫助初學者一點參考性的指導,當然也有很多的不足之處,如果有什麼更好的意見和實現的方法,請大牛們不吝指教,萬分感謝!

XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved