1.事件代理
- 事件代理:為子元素添加監(jiān)聽器轉(zhuǎn)變?yōu)闉楦溉萜魈砑颖O(jiān)聽器,然后通過event.target判斷具體操作的元素
- 事件的傳遞是和文檔結(jié)構(gòu)有關(guān)的
1.DOM0級和DOM2級在事件監(jiān)聽使用方式上有什么區(qū)別?
-
DOM0級事件處理程序
- 使用DOM0級方法指定的事件處理程序被認(rèn)為是元素的方法,因此,事件處理程序是在元素的作用域中運(yùn)行
var btn = document.getElementById('btn'); btn.onclick = function (){ console.log(this.id); // btn }- 使用DOM0級方法只能為元素的一個事件指定一個處理程序,后面指定的會覆蓋前面指定的(因?yàn)槭录幚沓绦虮徽J(rèn)為是元素的方法,同一事件則方法名相同)
// 后一個事件處理程序會覆蓋前一個事件處理程序 var btn = document.getElementById('btn'); btn.onclick = function (){ console.log(this.id); } btn.onclick = function (){ console.log("hello"); }- 使用DOM0級方法刪除事件處理程序
var btn = document.getElementById('btn'); btn.onclick = function (){ console.log(this.id); } btn.onclick = null;- 使用DOM0級方法指定的事件處理程序兼容IE較低版本
-
DOM2級事件處理程序
- 使用DOM2級方法指定的事件處理程序
var btn = document.getElementById('btn'); btn.addEventListener("click", function(){ console.log("test"); });function handler(){ console.log("test"); } var btn = document.getElementById('btn'); btn.addEventListener("click", handler);- 使用DOM2級方法可以為元素針對多個事件指定多個處理程序,這些事件處理程序會按照添加順序依次執(zhí)行
var btn = document.getElementById('btn'); function handler(){ console.log("test"); } btn.addEventListener("click", function(){ console.log("test"); }); btn.addEventListener("click", handler);- 使用DOM2級方法可以為元素刪除事件處理程序,但是指定的匿名事件處理函數(shù)無法刪除
btn.removeEventListener("click", handler);- 使用DOM2級事件處理程序可以指定在哪一階段調(diào)用事件處理程序(捕獲階段or冒泡階段)
btn.addEventListener("click", handler, false); // 在冒泡階段調(diào)用事件處理程序 btn.addEventListener("click", handler, true); // 在捕獲階段調(diào)用事件處理程序- 使用addEventListener為元素添加的事件處理程序也是在其依附的元素的作用域中運(yùn)行
var btn = document.getElementById('btn'); function handler(){ console.log(this.id); } btn.addEventListener("click", handler); // 觸發(fā)時輸出 btn
2.attachEvent與addEventListener的區(qū)別?
- 在低版本IE瀏覽器中,只支持事件冒泡,因此不支持addEventListener和removeEventListener方法,但是實(shí)現(xiàn)了類似的兩個方法:attachEvent和detachEvent
- addEventListener:
- 可以指定2或3個參數(shù)
- 可以指定在哪一階段調(diào)用事件處理程序(捕獲階段or冒泡階段),默認(rèn)是冒泡階段
- addEventListener第一個參數(shù)是事件類型(比如click,load)
- 為元素添加的事件處理程序是在其依附的元素的作用域中運(yùn)行
- addEventListener針對一個事件添加的多個事件處理程序會按照添加順序執(zhí)行
- attachEvent:
- 只能指定2個參數(shù)
- 添加的事件處理程序都會在冒泡階段被執(zhí)行,無法指定在哪一階段調(diào)用事件處理程序
- attachEvent第一個參數(shù)是事件處理函數(shù)名稱(比如onclick,onload)
- 為元素添加的事件處理程序是在全局作用域中運(yùn)行
- 事件處理函數(shù)名稱針對一個事件添加的多個事件處理程序會無規(guī)律執(zhí)行
3.解釋IE事件冒泡和DOM2事件傳播機(jī)制?
- IE的事件冒泡:事件開始時由最具體的元素接收,然后逐級向上傳播到較為不具體的元素
- Netscape的事件捕獲:不太具體的節(jié)點(diǎn)更早接收事件,而最具體的元素最后接收事件,和事件冒泡相反
- DOM事件流:DOM2級事件規(guī)定事件流包括三個階段,事件捕獲階段,處于目標(biāo)階段,事件冒泡階段,首先發(fā)生的是事件捕獲,為截取事件提供機(jī)會,然后是實(shí)際目標(biāo)接收事件,最后是冒泡階段
4.如何阻止事件冒泡? 如何阻止默認(rèn)事件?
- 阻止事件冒泡:event.stopPropagation();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<h1>hello!</h1>
</div>
<script>
var html = document.documentElement;
var body = document.body;
var div = document.querySelector("div");
var h1 = document.querySelector("h1");
window.addEventListener("click",function(){
console.log(1);
},true);
window.addEventListener("click",function(){
console.log(1);
});
document.addEventListener("click",function(){
console.log(2);
},true);
document.addEventListener("click",function(){
console.log(2);
});
html.addEventListener("click",function(){
console.log(3);
},true);
html.addEventListener("click",function(){
console.log(3);
});
body.addEventListener("click",function(){
console.log(4);
},true);
body.addEventListener("click",function(){
console.log(4);
});
div.addEventListener("click",function(){
console.log(5);
//如果沒有阻止捕獲/冒泡,點(diǎn)擊hello! 會輸出1 2 3 4 5 6 6 5 4 3 2 1
//如果阻止捕獲/冒泡,點(diǎn)擊hello! 會輸出1 2 3 4 5
event.stopPropagation();
},true);
div.addEventListener("click",function(){
console.log(5);
});
h1.addEventListener("click",function(){
console.log(6);
},true);
h1.addEventListener("click",function(){
console.log(6);
});
</script>
</body>
</html>
- 阻止默認(rèn)事件:event.preventDefault();
//阻止點(diǎn)擊a標(biāo)簽后導(dǎo)致的頁面跳轉(zhuǎn)
<a href="www.baidu.com" id="link">baidu</a>
<script>
function prevent(event){
event.preventDefault();
}
var link = document.getElementById("link");
link.addEventListener("click", prevent);
</script>
5.有如下代碼,要求當(dāng)點(diǎn)擊每一個元素li時控制臺展示該元素的文本內(nèi)容。
- 事件委托/事件代理:對于"事件處理程序過多"問題的解決方案就是事件委托/事件代理.事件委托利用了事件冒泡,只指定一個事件處理程序,就可以管理某一類型的所有事件.使用事件委托結(jié)束解決以下問題,只需要在DOM樹中盡量高的層次上添加一個事件處理程序.
<ul class="ct">
<li>aaaa</li>
<li>bbbb</li>
<li>cccc</li>
</ul>
<script>
function outputInnerText(event){
var target = event.target;
console.log(target.innerHTML);
}
var ul = document.querySelector(".ct");
ul.addEventListener("click", outputInnerText);
</script>
6.補(bǔ)全代碼,要求:
- 當(dāng)點(diǎn)擊按鈕開頭添加時在<li>這里是</li>元素前添加一個新元素,內(nèi)容為用戶輸入的非空字符串;當(dāng)點(diǎn)擊結(jié)尾添加時在最后一個 li 元素后添加用戶輸入的非空字符串.
- 當(dāng)點(diǎn)擊每一個元素li時控制臺展示該元素的文本內(nèi)容。
<div>
<ul class="ct">
<li>aaaa</li>
<li>bbbb</li>
<li>cccc</li>
</ul>
<input class="ipt-add-content" placeholder="添加內(nèi)容"/>
<button id="btn-add-start">開頭添加</button>
<button id="btn-add-end">結(jié)尾添加</button>
</div>
<script>
var ul = document.querySelector(".ct");
var btn_add_start = document.querySelector("#btn-add-start");
var btn_add_end = document.querySelector("#btn-add-end");
var content = document.querySelector(".ipt-add-content");
btn_add_start.onclick = function (event) {
if(content.value.length < 1 ){
alert('請輸入項(xiàng)目名稱');
}else{
var newNode = document.createElement("li");
newNode.innerHTML = content.value;
ul.insertBefore(newNode, ul.firstElementChild);
content.value = "";
}
}
btn_add_end.onclick = function (event) {
if(content.value.length < 1 ){
alert('請輸入項(xiàng)目名稱');
}else{
var newNode = document.createElement("li");
newNode.innerHTML = content.value;
ul.appendChild(newNode);
content.value = "";
}
}
function outputInnerText(event){
var target = event.target;
console.log(target.innerHTML);
}
ul.addEventListener("click", outputInnerText);
</script>
7.補(bǔ)全代碼,要求:當(dāng)鼠標(biāo)放置在li元素上,會在img-preview里展示當(dāng)前l(fā)i元素的data-img對應(yīng)的圖片。
<ul class="ct">
<li data-img="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1487859573373&di=7467cab77ceaa0739cb8a0acd5857623&imgtype=0&src=http%3A%2F%2Fwww.kele8.com%2Fuploadfile%2F2014%2F0326%2F20140326034001805.jpg">鼠標(biāo)放置查看圖片1</li>
<li data-img="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1487859916531&di=cbdd990e7d9dcbcb409168363182137a&imgtype=0&src=http%3A%2F%2Fh7.86.cc%2Fwalls%2F20150906%2F1024x768_43422cf79b8229f.jpg">鼠標(biāo)放置查看圖片2</li>
<li data-img="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1487859633187&di=b78c30783aaa1c04ef82ae6f398900fd&imgtype=0&src=http%3A%2F%2Fimg1.gamedog.cn%2F2014%2F04%2F22%2F43-1404221025080.jpg">鼠標(biāo)放置查看圖片3</li>
</ul>
<div class="img-preview"></div>
<script>
//使用事件代理/事件委托
var ul = document.querySelector(".ct");
var imgPreview = document.querySelector(".img-preview");
function agentMouseOver(event){
var target = event.target;
var imageName = target.getAttribute("data-img");
var image = document.createElement('img');
image.setAttribute("src", imageName);
if(imgPreview.firstElementChild != null){
imgPreview.replaceChild(image,imgPreview.firstElementChild );
}else{
imgPreview.appendChild(image);
imgPreview.firstElementChild.addEventListener("click", prevent);
}
}
ul.addEventListener("mouseover", agentMouseOver);
function closeImage(event){
if(imgPreview.firstElementChild != null){
imgPreview.removeEventListener("click", prevent);
imgPreview.removeChild(imgPreview.firstElementChild);
}
}
function prevent(event){
event.stopPropagation();
}
document.addEventListener("click", closeImage);
imgPreview.addEventListener("click", prevent);
</script>