1. 程式人生 > >事件流(事件冒泡和捕獲,函式閉包等)

事件流(事件冒泡和捕獲,函式閉包等)

事件流

事件流描述的是從頁面中接受事件的順序,當幾個都具有事件的元素層疊在一起的時候,那麼你點選其中一個元素,並不是只有當前被點選的元素會觸發事件,而層疊在你點選範圍的所有元素都會觸發事件。

事件流包括兩種模式:冒泡和捕獲

事件捕獲:

父級元素先觸發,子集元素後觸發;(由外到內)

事件冒泡:

子集元素先觸發,父級元素後觸;(由內到外)

子集元素和父元素具備同樣的事件,當觸發子元素時,也會觸發父元素的事件。

事件冒泡和事件捕獲例項

<!DOCTYPE html>
<html>
	<head>
		<meta
charset="UTF-8">
<title>事件冒泡和事件捕獲</title> <style type="text/css"> #bigDiv{ width: 400px; height: 400px; border: 1px solid #000; } #innerDiv{ width: 200px; height: 200px; border: 1px solid #AFEEEE; } </style> <script type="text/javascript">
window.onload=function(){ var bigDiv=document.getElementById('bigDiv'); var innerDiv=document.getElementById('innerDiv'); var arr=[bigDiv,innerDiv,document,document.body]; for (var i=0;i<arr.length;i++) { //傳統方式 // arr[i].onclick=function(){ // console.log(this); // } //通過Dom的經典方式新增事件
// addEventListener(引數1,引數2,引數3) // 引數1表示的是事件的型別 click,load,mousedown,blur,focus // 引數2表示的是事件的處理程式 // 引數3表示的是事件是否冒泡 true/false //表示的是事件的冒泡 設定值為false arr[i].addEventListener('click',show,false); //表示的是事件的捕獲 設定值為true // arr[i].addEventListener('click',show,true); } function show(){ console.log(this); } }
</script> </head> <body> <div id="bigDiv"> <div id="innerDiv"> </div> </div> </body> </html>

通過Dom的經典方式新增事件

addEventListener(引數1,引數2,引數3)
引數1表示的是事件的型別 click,load,mousedown,blur,focus
引數2表示的是事件的處理程式
引數3表示的是事件是否冒泡 true/false

事件冒泡測試結果(由內到外)
在這裡插入圖片描述

事件捕獲測試結果(由外到內)
在這裡插入圖片描述

事件相容

(1)事件繫結

addEventListener 用於註冊事件處理程式,IE 中為 attachEvent。

addEventListener 是 DOM 中的標準內容

//語法結構
element.addEventListener(event, function, useCapture)
//通過Dom的經典方式新增事件
//		addEventListener(引數1,引數2,引數3)
//		引數1表示的是事件的型別   click,load,mousedown,blur,focus
//		引數2表示的是事件的處理程式
//		引數3表示的是事件是否冒泡  true/false
//		注意:不要使用 "on" 字首。 例如,使用 "click" ,而不是使用 "onclick"。
//		可以使用函式名,來引用外部函式

事件繫結例項一

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>事件繫結</title>
		<script type="text/javascript">
			window.onload=function(){
				var btn=document.getElementById('txt');
			//匿名函式
//				btn.addEventListener('click',function(){
//					alert('事件註冊了');
//				})
			//有名函式
				btn.addEventListener('click',show);
			//下面這個有名函式放在window裡面或外面都OK
				function show(){
					alert('事件註冊了');
				}
			}
		</script>
	</head>
	<body>
		<input type="button" id="txt" value="事件註冊(事件繫結)" />
	</body>
</html>

事件繫結例項二

通過 addEventListener(新增點選事件監聽器)形式的繫結事件不會互相抵消,從而實現一個按鈕控制多個事件

(2)事件移除

**removeEventListener()**移除事件監聽器(不能使用匿名函式)

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>事件繫結和移除</title>
		<script type="text/javascript">
			window.onload=function(){
			//獲取頁面元素button
				var	btn2=document.getElementById('btn2');
			//註冊事件處理程式	addEventListener()
				btn2.addEventListener('click',show);
			//移除事件監聽器		removeEventListener()
//				btn2.removeEventListener('click',show);
			//下面這個有名函式放在window裡面或外面都OK
				function show(){
					console.log('第一個事件');
					console.log('第二個事件');
				}
			}
		</script>
	</head>
	<body>
		<button id="btn2">按鈕2</button>
	</body>
</html>

上面程式碼事件繫結測試結果為:
在這裡插入圖片描述

(3)獲取事件物件

事件物件封裝了事件發生的詳細資訊,尤其是滑鼠、鍵盤事件。如滑鼠事件發生的位置、鍵盤事件的鍵盤鍵等。

IE 中的事件物件:IE 中的事件物件是一個隱式可用的全域性物件:event,它是 window物件的一個屬性。

標準 DOM 的事件物件:在標準 DOM 瀏覽器檢測發生了某個事件時,將自動建立一個 Event物件,並隱式地將該物件作為事件處理函式的第一個引數傳入

案例一:

返回事件目標的名稱 使用屬性tagName

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>事件物件</title>
		<script type="text/javascript">
			window.onload=function(){
				var btn=document.getElementById('btn');
				btn.ondblclick=Myheader;
				function Myheader(e){
					if(window.event){
						e=window.event;
					}
				//相容低版本的IE瀏覽器
				var MyIE;
				if(e.srcElement){
					MyIE=e.srcElement;
				}else{
					MyIE=e.target;
				}
			//返回事件目標的名稱	使用屬性tagName
				alert(MyIE.tagName);
				}
			}
			
		</script>
	</head>
	<body>
		<button id="btn">請雙擊我</button>
	</body>
</html>

上面程式碼事件繫結測試結果為:
在這裡插入圖片描述

案例二(常用滑鼠事件物件)

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>常用滑鼠事件物件</title>
		<style type="text/css">
			#leftDIV{
				width: 200px;
				height: 200px;
				background: pink;
				float: left;
			}
			#rightDIV{
				width: 200px;
				height: 200px;
				border: 1px solid #000;
				float: left;
				overflow: auto;
			}
		</style>
	</head>
	<body>
		<div id="leftDIV"></div>
		<div id="rightDIV"></div>
		<script type="text/javascript">
//			var MyMouse=document.getElementById('leftDIV');
			var MyMouse=document.getElementById('leftDIV');
			var txt=document.getElementById('rightDIV');
			MyMouse.onclick=Myheader;
			MyMouse.ondblclick=Myheader;
			MyMouse.onmouseleave=Myheader;
			MyMouse.onmousedown=Myheader;
			MyMouse.onmouseup=Myheader;
			function Myheader(OEvent){
				if(window.event){
					OEvent=window.event;
				}
				txt.innerHTML+=OEvent.type+'\n';
			}
		</script>
	</body>
</html>

上面程式碼事件繫結測試結果為:
在這裡插入圖片描述

(4)阻止冒泡

event.stopPropagation() 阻止事件冒泡的產生

阻止冒泡案例

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>阻止事件冒泡</title>
		<style>
			#bigDIV{
				width: 400px;
				height: 400px;
				border: 20px solid greenyellow;
				position: relative;
			}
			#innerDIV{
				width: 200px;
				height: 200px;
				border: 20px solid orangered;
				position: absolute;
				left: 80px;
				top: 80px;
			}
			#span{
				display: inline-block;
				background: pink;
				margin: 90px 9px;
			}
		</style>
	</head>
	<body>
		<div id="bigDIV">
			<div id="innerDIV">
				<span id="span">這裡是最裡面的span標籤</span>
			</div>
		</div>
		<script type="text/javascript">
			var bigDIV=document.getElementById('bigDIV');
			var innerDIV=document.getElementById('innerDIV');
			var span=document.getElementById('span');
		//有名函式
//			bigDIV.addEventListener('click',show,false);
//			innerDIV.addEventListener('click',show,false);
//			span.addEventListener('click',show,false);
//			function show(event){
//				alert(this);
//			//阻止事件冒泡的產生	event.stopPropagation()
//				event.stopPropagation();
//			}
		//匿名函式
			bigDIV.addEventListener('click',function(event){
				alert('你點選了最外面的div');
				event.stopPropagation();
			},false);
			innerDIV.addEventListener('click',function(event){
				alert('你點選了第二層的div');
				event.stopPropagation();
			},false);
			span.addEventListener('click',function(event){
				alert('你點選了最裡面的span標籤');
				event.stopPropagation();
			},false);
		</script>
	</body>
</html>

(5)阻止預設

w3c 的方法是 e.preventDefault()

IE 則是使用 e.returnValue =false;

preventDefault 它是事件物件(Event)的一個方法,作用是取消一個目標元素的預設行為。比如超連結a

	<body>
		<a href="事件冒泡.html" target="_blank">啦啦啦啦啦</a>
		<script type="text/javascript">
			var a1=document.getElementsByTagName('a')[0];
		//傳統用法阻止事件的預設發生
//			a1.onclick=function(e){
//				e.preventDefault();
//			}
		//使用DOM方法來阻止預設發生
			a1.addEventListener('click',show);
		//相容
			function show(e){
				if (e.preventDefault) {
					e.preventDefault();
				} else{
					window.event.returnValue=false;
				}
			}
		</script>
	</body>

函式閉包

閉包是指有許可權訪問另一個函式作用域中的變數的函式。在 javascript 語言中,閉包就是函式和該函式作用域的組合。從這個概念上來講,在 js 中,所有函式都是閉包(函式都是物件並且函式都有和他們相關聯的作用域鏈 scope chain),但是巢狀的函式閉包作用會更大。

巢狀函式:

js中特殊的作用域鏈,父物件的所有變數對子物件都是可見的,反之則不成立。

閉包的應用(兩大作用)

①讀取函式內部的變數

②就是讓這些變數的值始終保持在記憶體中

案例一

		<script type="text/javascript">
		//閉包是指有許可權訪問另一個函式作用域中的變數的函式
		// 閉包就是函式和該函式作用域的組合
		//在js中,所有函式都是閉包(函式都是物件且函式都有他們相關聯的作用域鏈),但是巢狀的函式閉包作用會更大。
		//函式的巢狀:
			//js中特殊的作用域鏈:
			//父物件的所有變數,對子物件都是可見的,反之則不成立。
				function PiKaQiu(){
					var color='yellow';
					var weight=30;
					var height=20;
					function PiKaQiu_01(){
						alert(color);
					}
					PiKaQiu_01();
				}
				PiKaQiu();
				
			//使用return
				function cat(){
					var color='white';
					var height=20;
					var weight=50;
					function cat_01(){
						return color;
					}
					return cat_01();
				}
				alert(cat());
		</script>

案例二

		<script type="text/javascript">
			function cat(){
				var color='橘黃色';
				var height='又矮又胖';
				var weight='大肥貓';
				function cat_01(){
					return '這是一隻'+color+'的而且'+height+'的'+weight;
				}
				return cat_01();
			}
//			alert(cat());
			function Person(){
				alert(cat());
			}
			Person();
		//閉包函式的兩大作用:
			//1、可以讀取函式內部的變數
			//2、讓變數的值始終保持在記憶體中
		</script>

案例二程式碼測試結果為:
在這裡插入圖片描述