事件流(事件冒泡和捕獲,函式閉包等)
事件流
事件流描述的是從頁面中接受事件的順序,當幾個都具有事件的元素層疊在一起的時候,那麼你點選其中一個元素,並不是只有當前被點選的元素會觸發事件,而層疊在你點選範圍的所有元素都會觸發事件。
事件流包括兩種模式:冒泡和捕獲
事件捕獲:
父級元素先觸發,子集元素後觸發;(由外到內)
事件冒泡:
子集元素先觸發,父級元素後觸;(由內到外)
子集元素和父元素具備同樣的事件,當觸發子元素時,也會觸發父元素的事件。
事件冒泡和事件捕獲例項
<!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>
案例二程式碼測試結果為: