12_javascript事件

事件

事件,就是文檔或瀏覽器窗口中發生的一些特定的交互瞬間。

JavaScript 與 HTML 之間的交互是通過事件實現的。
對於 Web 應用來說,有下面這些代表性的事件:點擊某個元素、將鼠標移動至某個元素上方、
按下鍵盤上某個鍵等等。

我們可以在事件對應的屬性中設置一些js代碼,這樣當事件被觸發時,這些代碼將會執行。
這種寫法我們稱爲結構和行爲耦合,不方便維護,不推薦使用
<button id="btn" onmousemove="alert('討厭,你點我幹嘛!');">
	我是一個按鈕
</button>

可以爲按鈕的對應事件綁定處理函數的形式來響應事件,這樣當事件被觸發時,
其對應的函數將會被調用,像這種爲單擊事件綁定的函數,我們稱爲單擊響應函數。
// html
<button id="btn">我是一個按鈕</button>
// js
var btn = document.getElementById("btn");
btn.onclick = function(){
	alert("你還點~~~");
};	

常見的HTML事件:

事件 描述
onchange HTML 元素改變
onclick 用戶點擊 HTML 元素
onmouseover 用戶在一個HTML元素上移動鼠標
onmouseout 用戶從一個HTML元素上移開鼠標
onmousemove 鼠標在元素中移動時被觸發
onkeydown 用戶按下鍵盤按鍵
onload 瀏覽器已完成頁面的加載

事件的兼容

當事件的響應函數被觸發時,瀏覽器每次都會將一個事件對象作爲實參傳遞進響應函數,
在事件對象中封裝了當前事件相關的一切信息,比如:鼠標的座標、鍵盤哪個按鍵被按下、鼠標滾輪滾動的方向。。。

在IE8中,響應函數被觸發時,瀏覽器不會傳遞事件對象,在IE8及以下的瀏覽器中,
是將事件對象作爲window對象的屬性保存的。

// 解決事件對象的兼容性問題
event = event || window.event;

滾動條的兼容

chrome認爲瀏覽器的滾動條是body的,可以通過body.scrollTop來獲取;
火狐等瀏覽器認爲瀏覽器的滾動條是html的。

// 獲取滾動條滾動的距離
var st = document.body.scrollTop || document.documentElement.scrollTop;
var sl = document.body.scrollLeft || document.documentElement.scrollLeft;

事件的冒泡(Bubble)

所謂的冒泡指的就是事件的向上傳導,當後代元素上的事件被觸發時,
其祖先元素的相同事件也會被觸發

在開發中大部分情況冒泡都是有用的,如果不希望發生事件冒泡,可以通過事件對象來取消冒泡

取消冒泡:
w3c 的方法是 e.stopPropagation
IE 則是使用 e.cancelBubble = true
IE9 之前的IE不支持 stopPropagation() 方法。
相反,IE事件對象有一個 cancleBubble 屬性,設置這個屬性爲 true 能阻止事件進一步傳播。
( IE8 及之前版本不支持事件傳播的捕獲階段,所以冒泡是唯一待取消的事件傳播。)

// 取消事件冒泡兼容方法
function stopHandler(event){	
	window.event ? window.event.cancelBubble=true : event.stopPropagation();  
}  

事件的委派

爲每一個超鏈接都綁定一個單擊響應函數,這種操作比較麻煩,
而且這些操作只能爲已有的超鏈接設置事件,而新添加的超鏈接必須重新綁定。
我們希望,只綁定一次事件,即可應用到多個的元素上,
即使元素是後添加的也可以將事件綁定給元素的共同的祖先元素。 

事件的委派
指將事件統一綁定給元素的共同的祖先元素,這樣當後代元素上的事件觸發時,會一直冒泡到祖先元素,從而通過祖先元素的響應函數來處理事件。

事件委派是利用了冒泡,通過委派可以減少事件綁定的次數,提高程序的性能

event中的target表示的觸發事件的對象(event.target)

事件的綁定

使用 對象.事件 = 函數 的形式綁定響應函數,
它只能同時爲一個元素的一個事件綁定一個響應函數,不能綁定多個,如果綁定了多個,則後邊會覆蓋掉前邊的。

addEventListener()
通過這個方法也可以爲元素綁定多個響應函數

參數:
	1.事件的字符串,不要on
	2.回調函數,當事件觸發時該函數會被調用
	3.是否在捕獲階段觸發事件,需要一個布爾值,一般都傳false

使用addEventListener()可以同時爲一個元素的相同事件同時綁定多個響應函數
這樣當事件被觸發時,響應函數將會按照函數的綁定順序執行

這個方法不支持IE8及以下的瀏覽器

使用addEventListener()方法綁定響應函數,取消默認行爲時不能使用return false,
需要使用event來取消默認行爲event.preventDefault();
但是IE8不支持event.preventDefault()這個玩意,如果直接調用會報錯。
attachEvent()
在IE8中可以使用attachEvent()來綁定事件

使用 attachEvent 方法有個缺點,this 的值會變成 window 對象的引用而不是觸發事件的元素。

參數:
	1.事件的字符串,要on
	2.回調函數

這個方法也可以同時爲一個事件綁定多個處理函數,不同的是它是後綁定先執行,執行順序和addEventListener()相反。
綁定事件的兼容代碼:
// addEventListener()中的this,是綁定事件的對象
// attachEvent()中的this,是window
// 需要統一兩個方法this
/*
* 參數:
* 	el 要綁定事件的對象
* 	eventStr 事件的字符串(不要on)
*   callback 回調函數
*/
function bindEventListener(el , eventStr , callback){
	if(el.addEventListener){
		//大部分瀏覽器兼容的方式
		obj.addEventListener(eventStr , callback , false);
	}else{
		//IE8及以下
		obj.attachEvent("on"+eventStr , function(){
			// 在匿名函數中調用回調函數
			// 綁定this指向綁定事件的對象
			callback.call(el);
		});
	}
}

事件的傳播

關於事件的傳播網景公司和微軟公司有不同的理解:

微軟公司認爲事件應該是由內向外傳播,也就是當事件觸發時,
應該先觸發當前元素上的事件,然後再向當前元素的祖先元素上傳播,
也就說事件應該在冒泡階段執行。

網景公司認爲事件應該是由外向內傳播的,也就是當前事件觸發時,
應該先觸發當前元素的最外層的祖先元素的事件,然後在向內傳播給後代元素。

W3C綜合了兩個公司的方案,將事件傳播分成了三個階段
1. 捕獲階段
	在捕獲階段時從最外層的祖先元素,向目標元素進行事件的捕獲,
	但是默認此時不會觸發事件
2. 目標階段
	事件捕獲到目標元素,捕獲結束開始在目標元素上觸發事件
3. 冒泡階段
	事件從目標元素向他的祖先元素傳遞,依次觸發祖先元素上的事件,
	如果希望在捕獲階段就觸發事件,可以將addEventListener()的第三個參數設置爲true,
	一般情況下我們不會希望在捕獲階段觸發事件,所以這個參數一般都是false。

IE8及以下的瀏覽器中沒有捕獲階段。

自定義元素拖曳API

/*
 * 提取一個專門用來設置拖拽的函數
 * 參數:開啓拖拽的元素
 */
function drag(obj){
	//當鼠標在被拖拽元素上按下時,開始拖拽  onmousedown
	obj.onmousedown = function(event){
		
		//設置box1捕獲所有鼠標按下的事件
		/*
		 * setCapture()
		 * 	- 只有IE支持,但是在火狐中調用時不會報錯,
		 * 		而如果使用chrome調用,會報錯
		 */
		/*if(box1.setCapture){
			box1.setCapture();
		}*/
		obj.setCapture && obj.setCapture();
		
		
		event = event || window.event;
		//div的偏移量 鼠標.clentX - 元素.offsetLeft
		//div的偏移量 鼠標.clentY - 元素.offsetTop
		var ol = event.clientX - obj.offsetLeft;
		var ot = event.clientY - obj.offsetTop;
		//爲document綁定一個onmousemove事件
		document.onmousemove = function(event){
			event = event || window.event;
			//當鼠標移動時被拖拽元素跟隨鼠標移動 onmousemove
			//獲取鼠標的座標
			var left = event.clientX - ol;
			var top = event.clientY - ot;
			
			//修改box1的位置
			obj.style.left = left+"px";
			obj.style.top = top+"px";
			
		};	
		//爲document綁定一個鼠標鬆開事件
		document.onmouseup = function(){
			//當鼠標鬆開時,被拖拽元素固定在當前位置	onmouseup
			//取消document的onmousemove事件
			document.onmousemove = null;
			//取消document的onmouseup事件
			document.onmouseup = null;
			//當鼠標鬆開時,取消對事件的捕獲
			obj.releaseCapture && obj.releaseCapture();
		};
		/*
		 * 當我們拖拽一個網頁中的內容時,瀏覽器會默認去搜索引擎中搜索內容,
		 * 	此時會導致拖拽功能的異常,這個是瀏覽器提供的默認行爲,
		 * 	如果不希望發生這個行爲,則可以通過return false來取消默認行爲
		 * 
		 * 但是這招對IE8不起作用
		 */
		return false;
		
	};
}

滾輪事件

onmousewheel
鼠標滾輪滾動的事件,會在滾輪滾動時觸發,但是火狐不支持該屬性。

event.wheelDelta 可以獲取鼠標滾輪滾動的方向

向上滾 120 向下滾 -120
wheelDelta這個值我們不看大小,只看正負
wheelDelta這個屬性火狐中不支持
DOMMouseScroll
在火狐中需要使用 DOMMouseScroll 來綁定滾動事件,
注意該事件需要通過addEventListener()函數來綁定

在火狐中使用event.detail來獲取滾動的方向
向上滾 -3 向下滾 3 
和event.wheelDelta相反

使用addEventListener()方法綁定響應函數, 取消默認行爲時不能使用return false,
需要使用event來取消默認行爲event.preventDefault();
但是IE8不支持event.preventDefault();這個玩意,

event.preventDefault && event.preventDefault(); 
滾輪事件Demo:
元素隨鼠標滾輪變長或縮短

// Html:
<body style="height: 2000px;">
	<div id="box1"></div>
</body>

// css:
<style type="text/css">
	#box1{
		width: 100px;
		height: 100px;
		background-color: red;
	}	
</style>

// js:
window.onload = function(){
	//獲取id爲box1的div
	var box1 = document.getElementById("box1");
	//爲box1綁定一個鼠標滾輪滾動的事件
	/*
	 * onmousewheel鼠標滾輪滾動的事件,
	 * 會在滾輪滾動時觸發,
	 * 	但是火狐不支持該屬性
	 * 
	 * 在火狐中需要使用 DOMMouseScroll 來綁定滾動事件
	 * 注意該事件需要通過addEventListener()函數來綁定
	 */
	box1.onmousewheel = function(event){
		event = event || window.event;
		//event.wheelDelta 可以獲取鼠標滾輪滾動的方向
		//向上滾 120   向下滾 -120
		//wheelDelta這個值我們不看大小,只看正負		
		//wheelDelta這個屬性火狐中不支持
		//在火狐中使用event.detail來獲取滾動的方向
		//向上滾 -3  向下滾 3
		/*
		 * 當鼠標滾輪向下滾動時,box1變長
		 * 	當滾輪向上滾動時,box1變短
		 */
		//判斷鼠標滾輪滾動的方向
		if(event.wheelDelta > 0 || event.detail < 0){
			//向上滾,box1變短
			box1.style.height = box1.clientHeight - 10 + "px";
		}else{
			//向下滾,box1變長
			box1.style.height = box1.clientHeight + 10 + "px";
		}
		/*
		 * 使用addEventListener()方法綁定響應函數,
		 * 取消默認行爲時不能使用return false
		 * 需要使用event來取消默認行爲event.preventDefault();
		 * 但是IE8不支持event.preventDefault();這個玩意,如果直接調用會報錯
		 */
		event.preventDefault && event.preventDefault();
		/*
		 * 當滾輪滾動時,如果瀏覽器有滾動條,
		 * 滾動條會隨之滾動,
		 * 這是瀏覽器的默認行爲,如果不希望發生,則可以取消默認行爲
		 */
		return false;	
	};
	
	//爲火狐綁定滾輪事件
	bindEventListener(box1,"DOMMouseScroll",box1.onmousewheel);
};

function bindEventListener(obj , eventStr , callback){
	if(obj.addEventListener){
		//大部分瀏覽器兼容的方式
		obj.addEventListener(eventStr , callback , false);
	}else{
		//IE8及以下
		obj.attachEvent("on"+eventStr , function(){
			//在匿名函數中調用回調函數
			callback.call(obj);
		});
	}
}

鍵盤事件:

onkeydown
    按鍵被按下
    對於onkeydown來說如果一直按着某個按鍵不鬆手,
    則事件會一直觸發
    當onkeydown連續觸發時,第一次和第二次之間會間隔稍微長一點,
    其他的會非常的快這種設計是爲了防止誤操作的發生。
    
onkeyup
    按鍵被鬆開

鍵盤事件一般都會綁定給一些可以獲取到焦點的對象或者是document。
發佈了61 篇原創文章 · 獲贊 0 · 訪問量 4324
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章