元旦過后蛾扇,新年第一篇。
初衷:很多的面試都會(huì)涉及到事件委托魏滚,前前后后也看過好多博文镀首,寫的都很不錯(cuò),寫的各有千秋鼠次,自己思前想后更哄,為了以后自己的查看,也同時(shí)為現(xiàn)在找工作的前端小伙伴提供一個(gè)看似更全方位的解讀事件委托的地方來認(rèn)識(shí)了解他的原理腥寇,本篇文章匯總了兩個(gè)版本的事件委托:javascript成翩、jquery;
事件委托的定義:
利用事件冒泡,只指定一個(gè)事件處理程序赦役,就可以管理某一類型的所有事件麻敌。
事件委托的優(yōu)勢:
- 在js中添加到頁面上的事件處理程序的個(gè)數(shù)直接影響到網(wǎng)頁的運(yùn)行性能。因?yàn)槊總€(gè)事件處理函數(shù)都是一個(gè)對象掂摔,是對象就會(huì)占用內(nèi)存术羔,而內(nèi)存中對象越多,導(dǎo)致的結(jié)果就是性能越差乙漓;而訪問dom的次數(shù)越多级历,就會(huì)引起結(jié)構(gòu)的重繪或者重排的次數(shù)也隨之增多,會(huì)延遲整個(gè)頁面的交互就緒時(shí)間叭披;
- 對于在頁面進(jìn)行處理過后新增的dom元素寥殖,運(yùn)用事件委托可以為新增的dom元素一并增減事件處理程序;
在下面的代碼中p標(biāo)簽要實(shí)現(xiàn)的效果是鼠標(biāo)點(diǎn)擊p標(biāo)簽的時(shí)候背景色變?yōu)榧t色涩蜘,以下是js嚼贡、jq的處理方法
<body>
<div id="nodes">
<P class="node_p">第一個(gè)p</P>
<P class="node_p">第二個(gè)p</P>
<P class="node_p">第三個(gè)p</P>
<div id="childDiv">
<p>這是子集菜單</p>
<div>我是子集的div
<p>我是子集的p</p>
</div>
</div>
</div>
<button>點(diǎn)擊加一</button>
</body>
一、js事件委托
在js中不用事件委托的情況:獲取頁面中所有的p標(biāo)簽然后用for循環(huán)遍歷給每一個(gè)元素增加事件處理函數(shù)
let nodes = document.getElementById("nodes");
let ps = document.getElementsByTagName("p");
console.log(ps);
let btn = document.getElementsByTagName("button")[0];
let inner = 33;
btn.onclick = function() {
inner++;
let p = document.createElement("p");
p.innerHTML = inner + "新增的p標(biāo)簽啊";
nodes.appendChild(p);
console.log(ps);
};
for (let i= 0;i<ps.length;i++){
ps[i].onclick= function(){
this.style.background = 'red'
}
}
這時(shí)候在瀏覽器中運(yùn)行之后進(jìn)行測試同诫,發(fā)現(xiàn)如圖一所示的結(jié)果粤策;
那么js不用事件委托怎么給新增加的標(biāo)簽添加事件處理函數(shù)呢?解決方案如下:
let nodes = document.getElementById("nodes");
let ps = document.getElementsByTagName("p");
console.log(ps);
let btn = document.getElementsByTagName("button")[0];
let inner = 33;
btn.onclick = function () {
inner++;
let p = document.createElement("p");
p.innerHTML = inner + "新增的p標(biāo)簽啊";
nodes.appendChild(p);
addEvent();//將新dom元素增加到頁面后再執(zhí)行循環(huán)函數(shù)
console.log(ps);
};
function addEvent() {
for (let i = 0; i < ps.length; i++) {
ps[i].onclick = function () {
this.style.background = 'red'
}
}
}
addEvent() //先執(zhí)行一遍循環(huán)
這時(shí)候?yàn)g覽器中運(yùn)行如圖二所示:
這時(shí)候雖然解決了為新增dom元素增加事件處理函數(shù)的問題剩辟,但是仔細(xì)考慮他的性能卻是比之前都有所下降,究其原因就是又增加了一個(gè)事件處理函數(shù)(對象),又一次占用了內(nèi)存贩猎;所以熊户,這個(gè)時(shí)候就會(huì)用到事件委托,這時(shí)候事件委托的優(yōu)勢也有所體現(xiàn)出來:
let nodes = document.getElementById("nodes");
let ps = document.getElementsByTagName("p");
console.log(ps);
let btn = document.getElementsByTagName("button")[0];
let inner = 33;
btn.onclick = function () {
inner++;
let p = document.createElement("p");
p.innerHTML = inner + "新增的p標(biāo)簽啊";
nodes.appendChild(p);
console.log(ps);
};
//事件委托吭服,為nodes指定一個(gè)事件處理函數(shù)嚷堡,處理nodes下為p標(biāo)簽的所有元素的cilck事件
nodes.onclick= function(e){
let ev = e || window.event
let target = ev.target || ev.srcElement //srcElement IE瀏覽器
//這里要判被處理元素節(jié)點(diǎn)的名字,也可以增加相應(yīng)的判斷條件 target.nodeName.toLowerCase() == 'p'||target.nodeName.toLowerCase() == 'span',但是要注意不要使用父級元素的名稱艇棕,因?yàn)樵冱c(diǎn)擊子元素之間的空氣的時(shí)候蝌戒,由于事件冒泡他會(huì)給父級元素也增加相應(yīng)的事件處理函數(shù);因?yàn)榉祷氐墓?jié)點(diǎn)名稱一般都是大寫沼琉,所以這時(shí)要用toLowerCase()處理一下北苟;
if(target.nodeName.toLowerCase() == 'p'){
target.style.background = 'green'
}
}
這時(shí)候?yàn)g覽器中運(yùn)行的結(jié)果如圖三所示:
二、jquery事件委托:
相較于js事件委托打瘪,jquery事件委托的優(yōu)勢:執(zhí)行事件委托的時(shí)候只有子元素會(huì)觸發(fā)事件函數(shù)友鼻,而代為執(zhí)行的父元素不會(huì)觸發(fā)事件函數(shù),因此不用去判斷元素節(jié)點(diǎn)的名稱闺骚;(注意這里的事件委托用的方法on,如果用bind方法父元素會(huì)觸發(fā)事件函數(shù))
這里nodes節(jié)點(diǎn)下所有標(biāo)簽為p的子節(jié)點(diǎn)都被賦予事件處理函數(shù)彩扔;這里的子節(jié)點(diǎn)還可以是多個(gè)類似' p,span',需要注意這里面也不可以寫同nodes一樣的標(biāo)簽,否則點(diǎn)擊元素之間的間隔會(huì)給nodes下的div賦予事件處理函數(shù)僻爽;如例二:
例一:
let inner = 33;
//這里nodes節(jié)點(diǎn)下所有標(biāo)簽為p的子節(jié)點(diǎn)都被賦予事件處理函數(shù)虫碉;這里的子節(jié)點(diǎn)還可以是多個(gè)類似' p,span',需要注意這里面也不可以寫同nodes一樣的標(biāo)簽,否則點(diǎn)擊元素之間的間隔會(huì)給nodes下的div賦予事件處理函數(shù)
$('#nodes').on('click','p',function(e){
let target = $(e.target)
target.css('backgroundColor','red')
})
$('button').click(()=>{
inner++;
$('#nodes').append($('<p>我是新增加的p標(biāo)簽'+inner+'</p>'))
})
瀏覽器運(yùn)行的效果如圖四所示:
例二:
<body>
<div id="nodes">
<P class="node_p">第一個(gè)p</P>
<P class="node_p">第二個(gè)p</P>
<P class="node_p">第三個(gè)p</P>
<span class="node_p">span</span>
<div id="childDiv">
<p>這是子集菜單</p>
<div>我是子集的div
<p>我是子集的p</p>
</div>
</div>
</div>
<button>點(diǎn)擊加一</button>
</body>
<script>
let inner =33;
$('#nodes').on('click','p,div,span',function(e){
let target = $(e.target)
target.css('backgroundColor','red')
})
$('button').click(()=>{
inner++;
$('#nodes').append($('<p>我是新增加的p標(biāo)簽'+inner+'</p>'))
})
</script>
瀏覽器運(yùn)行效果如圖五所示:
事件委托不僅僅只是為處理一種dom操作類型胸梆,他可以進(jìn)行增刪改查等功能:
js事件委托:不同操作
<body>
<div id="events">
<input type="button" id='addHandle' value='增加'>
<input type="button" id='deleteHandle' value='減少'>
</div>
<div id="content">
</div>
</body>
<script src='http://code.jquery.com/jquery-2.1.1.min.js'></script>
<script>
let events = document.getElementById('events');
let content = document.getElementById('content');
events.onclick=function(e){
let ev = e || window.event;
let target = ev.target || ev.srcElement;
if(target.nodeName.toLowerCase()=='input'){
switch(target.id){
case 'addHandle':
return addEvent();
break
case 'deleteHandle':
return deleteEvent();
break
}
}
}
function addEvent(){
let add = document.createElement('p')
add.innerHTML = '這是增加按鈕'
content.appendChild(add)
}
function deleteEvent(){
let del = document.createElement('p')
del.innerHTML = '這是刪除按鈕'
content.appendChild(del)
}
</script>
瀏覽器中的效果如圖六所示:
jquery事件委托:不同操作
$('#events').on('click','input',(e)=>{
let target = $(e.target);
switch(target[0].id){
case 'addHandle':
return addEvent();
break
case 'deleteHandle':
return deleteEvent();
break
}
})
function addEvent(){
$('#content').append($('<div>這是增加按鈕</div>'))
}
function deleteEvent(){
$('#content').append($('<div>這是刪除按鈕</div>'))
}
瀏覽器中的效果如圖七所示:
本文如有不實(shí)之處敦捧,還望大神指點(diǎn)一二,歡迎討論乳绕!