1.1. 事件高級
1.1.1. 注冊事件(2種方式)
1.1.2 事件監(jiān)聽
addEventListener()事件監(jiān)聽(IE9以后支持)
eventTarget.addEventListener()方法將指定的監(jiān)聽器注冊到 eventTarget(目標(biāo)對象)上,當(dāng)該對象觸發(fā)指定的事件時级历,就會執(zhí)行事件處理函數(shù)释移。
attacheEvent()事件監(jiān)聽(IE678支持)
? eventTarget.attachEvent()方法將指定的監(jiān)聽器注冊到 eventTarget(目標(biāo)對象) 上,當(dāng)該對象觸發(fā)指定的事件時寥殖,指定的回調(diào)函數(shù)就會被執(zhí)行玩讳。
<button>傳統(tǒng)注冊事件</button>
<button>方法監(jiān)聽注冊事件</button>
<button>ie9 attachEvent</button>
<script>
var btns = document.querySelectorAll('button');
// 1. 傳統(tǒng)方式注冊事件
btns[0].onclick = function() {
alert('hi');
}
btns[0].onclick = function() {
alert('hao a u');
}
// 2. 事件偵聽注冊事件 addEventListener
// (1) 里面的事件類型是字符串 必定加引號 而且不帶on
// (2) 同一個元素 同一個事件可以添加多個偵聽器(事件處理程序)
btns[1].addEventListener('click', function() {
alert(22);
})
btns[1].addEventListener('click', function() {
alert(33);
})
// 3. attachEvent ie9以前的版本支持
btns[2].attachEvent('onclick', function() {
alert(11);
})
</script>
事件監(jiān)聽兼容性解決方案
封裝一個函數(shù),函數(shù)中判斷瀏覽器的類型:
1.1.3. 刪除事件(解綁事件)
<div>1</div>
<div>2</div>
<div>3</div>
<script>
var divs = document.querySelectorAll('div');
divs[0].onclick = function() {
alert(11);
// 1. 傳統(tǒng)方式刪除事件
divs[0].onclick = null;
}
// 2. removeEventListener 刪除事件
divs[1].addEventListener('click', fn) // 里面的fn 不需要調(diào)用加小括號
function fn() {
alert(22);
divs[1].removeEventListener('click', fn);
}
// 3. detachEvent
divs[2].attachEvent('onclick', fn1);
function fn1() {
alert(33);
divs[2].detachEvent('onclick', fn1);
}
</script>
**刪除事件兼容性解決方案 **
1.1.4. DOM事件流
html中的標(biāo)簽都是相互嵌套的嚼贡,我們可以將元素想象成一個盒子裝一個盒子熏纯,document是最外面的大盒子。
當(dāng)你單擊一個div時,同時你也單擊了div的父元素,甚至整個頁面窄坦。那么是先執(zhí)行父元素的單擊事件榛搔,還是先執(zhí)行div的單擊事件 ?坛猪??
比如:我們給頁面中的一個div注冊了單擊事件,當(dāng)你單擊了div時萍膛,也就單擊了body,單擊了html嚷堡,單擊了document蝗罗。
當(dāng)時的2大瀏覽器霸主誰也不服誰!
IE 提出從目標(biāo)元素開始蝌戒,然后一層一層向外接收事件并響應(yīng)串塑,也就是冒泡型事件流。
Netscape(網(wǎng)景公司)提出從最外層開始北苟,然后一層一層向內(nèi)接收事件并響應(yīng)桩匪,也就是捕獲型事件流。江湖紛爭友鼻,武林盟主也腦殼疼I店肌9肷А!
最終妆档,w3c 采用折中的方式僻爽,平息了戰(zhàn)火,制定了統(tǒng)一的標(biāo)準(zhǔn) —--— 先捕獲再冒泡贾惦。
現(xiàn)代瀏覽器都遵循了此標(biāo)準(zhǔn)胸梆,所以當(dāng)事件發(fā)生時,會經(jīng)歷3個階段须板。
DOM 事件流會經(jīng)歷3個階段:
捕獲階段
當(dāng)前目標(biāo)階段
冒泡階段
? 我們向水里面扔一塊石頭碰镜,首先它會有一個下降的過程,這個過程就可以理解為從最頂層向事件發(fā)生的最具體元素(目標(biāo)點)的捕獲過程习瑰;之后會產(chǎn)生泡泡绪颖,會在最低點( 最具體元素)之后漂浮到水面上,這個過程相當(dāng)于事件冒泡杰刽。
事件冒泡
<div class="father">
<div class="son">son盒子</div>
</div>
<script>
// onclick 和 attachEvent(ie) 在冒泡階段觸發(fā)
// 冒泡階段 如果addEventListener 第三個參數(shù)是 false 或者 省略
// son -> father ->body -> html -> document
var son = document.querySelector('.son');
// 給son注冊單擊事件
son.addEventListener('click', function() {
alert('son');
}, false);
// 給father注冊單擊事件
var father = document.querySelector('.father');
father.addEventListener('click', function() {
alert('father');
}, false);
// 給document注冊單擊事件菠发,省略第3個參數(shù)
document.addEventListener('click', function() {
alert('document');
})
</script>
事件捕獲
<div class="father">
<div class="son">son盒子</div>
</div>
<script>
// 如果addEventListener() 第三個參數(shù)是 true 那么在捕獲階段觸發(fā)
// document -> html -> body -> father -> son
var son = document.querySelector('.son');
// 給son注冊單擊事件,第3個參數(shù)為true
son.addEventListener('click', function() {
alert('son');
}, true);
var father = document.querySelector('.father');
// 給father注冊單擊事件贺嫂,第3個參數(shù)為true
father.addEventListener('click', function() {
alert('father');
}, true);
// 給document注冊單擊事件滓鸠,第3個參數(shù)為true
document.addEventListener('click', function() {
alert('document');
}, true)
</script>
1.1.5. 事件對象
什么是事件對象
事件發(fā)生后,跟事件相關(guān)的一系列信息數(shù)據(jù)的集合都放到這個對象里面第喳,這個對象就是事件對象糜俗。
比如:
誰綁定了這個事件。
鼠標(biāo)觸發(fā)事件的話曲饱,會得到鼠標(biāo)的相關(guān)信息悠抹,如鼠標(biāo)位置。
鍵盤觸發(fā)事件的話扩淀,會得到鍵盤的相關(guān)信息楔敌,如按了哪個鍵。
事件對象的使用
事件觸發(fā)發(fā)生時就會產(chǎn)生事件對象驻谆,并且系統(tǒng)會以實參的形式傳給事件處理函數(shù)卵凑。
所以,在事件處理函數(shù)中聲明1個形參用來接收事件對象胜臊。
事件對象的兼容性處理
事件對象本身的獲取存在兼容問題:
標(biāo)準(zhǔn)瀏覽器中是瀏覽器給方法傳遞的參數(shù)勺卢,只需要定義形參 e 就可以獲取到。
在 IE6~8 中象对,瀏覽器不會給方法傳遞參數(shù)黑忱,如果需要的話,需要到 window.event 中獲取查找。
只要“||”前面為false, 不管“||”后面是true 還是 false甫煞,都返回 “||” 后面的值菇曲。
只要“||”前面為true, 不管“||”后面是true 還是 false,都返回 “||” 前面的值抚吠。
<div>123</div>
<script>
var div = document.querySelector('div');
div.onclick = function(e) {
// 事件對象
e = e || window.event;
console.log(e);
}
</script>
// 1. event 就是一個事件對象 寫到我們偵聽函數(shù)的 小括號里面 當(dāng)形參來看
// 2. 事件對象只有有了事件才會存在羊娃,它是系統(tǒng)給我們自動創(chuàng)建的,不需要我們傳遞參數(shù)
// 3. 事件對象 是 我們事件的一系列相關(guān)數(shù)據(jù)的集合 跟事件相關(guān)的 比如鼠標(biāo)點擊里面就包含了鼠標(biāo)的相關(guān)信息埃跷,鼠標(biāo)坐標(biāo)啊,如果是鍵盤事件里面就包含的鍵盤事件的信息 比如 判斷用戶按下了那個鍵
// 4. 這個事件對象我們可以自己命名 比如 event 邮利、 evt弥雹、 e
// 5. 事件對象也有兼容性問題 ie678 通過 window.event 兼容性的寫法 e = e || window.event;
事件對象的屬性和方法
e.target 和 this 的區(qū)別
this 是事件綁定的元素(綁定這個事件處理函數(shù)的元素) 。
e.target 是事件觸發(fā)的元素延届。
通常情況下terget 和 this是一致的剪勿,
但有一種情況不同,那就是在事件冒泡時(父子元素有相同事件方庭,單擊子元素厕吉,父元素的事件處理函數(shù)也會被觸發(fā)執(zhí)行),
這時候this指向的是父元素械念,因為它是綁定事件的元素對象头朱,
而target指向的是子元素,因為他是觸發(fā)事件的那個具體元素對象龄减。
<div>123</div>
<script>
var div = document.querySelector('div');
div.addEventListener('click', function(e) {
// e.target 和 this指向的都是div
console.log(e.target);
console.log(this);
});
</script>
事件冒泡下的e.target和this
<ul>
<li>abc</li>
<li>abc</li>
<li>abc</li>
</ul>
<script>
var ul = document.querySelector('ul');
ul.addEventListener('click', function(e) {
// 我們給ul 綁定了事件 那么this 就指向ul
console.log(this); // ul
// e.target 觸發(fā)了事件的對象 我們點擊的是li e.target 指向的就是li
console.log(e.target); // li
});
</script>
1.1.6 阻止默認(rèn)行為
html中一些標(biāo)簽有默認(rèn)行為项钮,例如a標(biāo)簽被單擊后,默認(rèn)會進(jìn)行頁面跳轉(zhuǎn)希停。
<div>123</div>
<a >百度</a>
<form action="http://www.baidu.com">
<input type="submit" value="提交" name="sub">
</form>
<script>
// 常見事件對象的屬性和方法
// 1. 返回事件類型
var div = document.querySelector('div');
div.addEventListener('click', fn);
div.addEventListener('mouseover', fn);
div.addEventListener('mouseout', fn);
function fn(e) {
console.log(e.type);
}
// 2. 阻止默認(rèn)行為(事件) 讓鏈接不跳轉(zhuǎn) 或者讓提交按鈕不提交
var a = document.querySelector('a');
a.addEventListener('click', function(e) {
e.preventDefault(); // dom 標(biāo)準(zhǔn)寫法
})
// 3. 傳統(tǒng)的注冊方式
a.onclick = function(e) {
// 普通瀏覽器 e.preventDefault(); 方法
// e.preventDefault();
// 低版本瀏覽器 ie678 returnValue 屬性
// e.returnValue;
// 我們可以利用return false 也能阻止默認(rèn)行為 沒有兼容性問題 特點: return 后面的代碼不執(zhí)行了烁巫, 而且只限于傳統(tǒng)的注冊方式
return false;
alert(11);
}
</script>
1.1.7 阻止事件冒泡
事件冒泡本身的特性,會帶來的壞處宠能,也會帶來的好處亚隙。
<div class="father">
<div class="son">son兒子</div>
</div>
<script>
var son = document.querySelector('.son');
// 給son注冊單擊事件
son.addEventListener('click', function(e) {
alert('son');
e.stopPropagation(); // stop 停止 Propagation 傳播
window.event.cancelBubble = true; // 非標(biāo)準(zhǔn) cancel 取消 bubble 泡泡
}, false);
var father = document.querySelector('.father');
// 給father注冊單擊事件
father.addEventListener('click', function() {
alert('father');
}, false);
// 給document注冊單擊事件
document.addEventListener('click', function() {
alert('document');
})
</script>
阻止事件冒泡的兼容性處理
1.1.8 事件委托
事件冒泡本身的特性,會帶來的壞處违崇,也會帶來的好處阿弃。
什么是事件委托
把事情委托給別人,代為處理亦歉。
事件委托也稱為事件代理恤浪,在 jQuery 里面稱為事件委派。
說白了就是肴楷,不給子元素注冊事件水由,給父元素注冊事件,把處理代碼在父元素的事件中執(zhí)行赛蔫。
生活中的代理:
js事件中的代理:
事件委托的原理
? 給父元素注冊事件砂客,利用事件冒泡泥张,當(dāng)子元素的事件觸發(fā),會冒泡到父元素鞠值,然后去控制相應(yīng)的子元素媚创。
事件委托的作用
我們只操作了一次 DOM ,提高了程序的性能彤恶。
動態(tài)新創(chuàng)建的子元素钞钙,也擁有事件。
<ul>
<li>知否知否声离,點我應(yīng)有彈框在手芒炼!</li>
<li>知否知否,點我應(yīng)有彈框在手术徊!</li>
<li>知否知否本刽,點我應(yīng)有彈框在手!</li>
<li>知否知否赠涮,點我應(yīng)有彈框在手子寓!</li>
<li>知否知否,點我應(yīng)有彈框在手笋除!</li>
</ul>
<script>
// 事件委托的核心原理:給父節(jié)點添加偵聽器斜友, 利用事件冒泡影響每一個子節(jié)點
var ul = document.querySelector('ul');
ul.addEventListener('click', function(e) {
// e.target 這個可以得到我們點擊的對象
e.target.style.backgroundColor = 'pink';
})
</script>