先來上一段個(gè)人總結(jié)的理解
1/事件分為三個(gè)部分
(1)捕獲階段
(2)目標(biāo)階段
(3)冒泡階段
事件冒泡
1/阻止事件冒泡是對(duì)同類名事件而言 (為什么得出這個(gè)結(jié)論呢: 在父元素和子元素 寫的事件都不一樣,mousedown ,mouseup , mouseove ,fouce,blur 都嘗試寫了阻斷,當(dāng)時(shí)都沒發(fā)阻止最上面的onclick的事件發(fā)生頁面最后又案例.,后續(xù)又試驗(yàn)了給父元素和子元素都只添加mousedown,發(fā)現(xiàn)阻斷是有效的,后面有案例 )
2/事件冒泡的形象圖:
請(qǐng)注意一點(diǎn):默認(rèn)是冒泡的,若是變捕獲,需要改變addEventListener的第三個(gè)值
(1):false 默認(rèn)值 冒泡
(2):true 不冒泡 捕獲
事件對(duì)象:事件特有的對(duì)象,e 是變量名,常用的名字,可以為任何名字
document.onclick = functionl(e){ //e 可以為任何名字,建議用e //e有內(nèi)容 常見的有 // e.target 目標(biāo) //e.type 事件類型 ..... //當(dāng)點(diǎn)擊的內(nèi)容是document本身,那么e.target === this //true //當(dāng)點(diǎn)擊的內(nèi)容是它內(nèi)部的div元素,那么e.target ===this //false }
//事件委托
什么是委托?
語言的含義: 我把一些感覺可以讓別人幫忙處理的問題委托給別人處理.
在此處在舉一個(gè)例子: 公司前臺(tái)MM收快遞
那什么叫事件委托呢?它還有一個(gè)名字叫事件代理,JavaScript高級(jí)程序設(shè)計(jì)上講:事件委托就是利用事件冒泡,只指定一個(gè)事件處理程序,就可以管理某一類型的所有事件。那這是什么意思呢?網(wǎng)上的各位大牛們講事件委托基本上都用了同一個(gè)例子,就是取快遞來解釋這個(gè)現(xiàn)象,我仔細(xì)揣摩了一下,這個(gè)例子
還真是恰當(dāng),我就不去想別的例子來解釋了,借花獻(xiàn)佛,我摘過來,大家認(rèn)真領(lǐng)會(huì)一下事件委托到底是一個(gè)什么原理: 有三個(gè)同事預(yù)計(jì)會(huì)在周一收到快遞。為簽收快遞,有兩種辦法:一是三個(gè)人在公司門口等快遞;二是委托給前臺(tái)MM代為簽收?,F(xiàn)實(shí)當(dāng)中,我們大都采用委托的方案(公司也不會(huì)容忍那么多員工站在門口就為了等快遞)。前臺(tái)MM收到快遞后,她會(huì)判斷收件人是誰,然后按照收件人的要求簽收,甚至代為付款。
這種方案還有一個(gè)優(yōu)勢(shì),那就是即使公司里來了新員工(不管多少),前臺(tái)MM也會(huì)在收到寄給新員工的快遞后核實(shí)并代為簽收。 這里其實(shí)還有2層意思的: 第一,現(xiàn)在委托前臺(tái)的同事是可以代為簽收的,即程序中的現(xiàn)有的dom節(jié)點(diǎn)是有事件的; 第二,新員工也是可以被前臺(tái)MM代為簽收的,即程序中新添加的dom節(jié)點(diǎn)也是有事件的。
第二個(gè)點(diǎn)讓我聯(lián)想思考了冒泡事件的第二個(gè)階段
事件委托的原理(主要理解target屬性)::
就是利用事件冒泡原理(請(qǐng)先理解冒泡),然后通過target屬性,返回事件的目標(biāo)節(jié)點(diǎn),稱為事件源,可以理解為target是實(shí)際點(diǎn)擊的哪個(gè)標(biāo)簽(dom),但不是實(shí)際的dom.
window.onload = function(){
var oUl = document.getElementById("ul1");
oUl.onclick = function(ev){
var ev = ev || window.event;
var target = ev.target || ev.srcElement;
if(target.nodeName.toLowerCase() == 'li'){
alert(123);
alert(target.innerHTML);
}
}
}
借鑒別人的代碼,真的很經(jīng)典,點(diǎn)個(gè)贊
為什么要用事件委托?
一般來說,dom需要有事件處理程序,我們都會(huì)直接給它設(shè)事件處理程序就好了,那如果是很多的dom需要添加事件處理呢?比如我們有100個(gè)li,每個(gè)li都有相同的click點(diǎn)擊事件,可能我們會(huì)用for循環(huán)的方法,來遍歷所有的li,然后給它們添加事件,那這么做會(huì)存在什么影響呢? 在JavaScript中,添加到頁面上的事件處理程序數(shù)量將直接關(guān)系到頁面的整體運(yùn)行性能,因?yàn)樾枰粩嗟呐cdom節(jié)點(diǎn)進(jìn)行交互,訪問dom的次數(shù)越多,引起瀏覽器重繪與重排的次數(shù)也就越多,就會(huì)延長整個(gè)頁面的交互就緒時(shí)間,這就是為什么性能優(yōu)化的主要思想之一就是減少DOM操作的原因;如果要用事件委托,
就會(huì)將所有的操作放到j(luò)s程序里面,與dom的操作就只需要交互一次,這樣就能大大的減少與dom的交互次數(shù),提高性能; 每個(gè)函數(shù)都是一個(gè)對(duì)象,是對(duì)象就會(huì)占用內(nèi)存,對(duì)象越多,內(nèi)存占用率就越大,自然性能就越差了(內(nèi)存不夠用,是硬傷,哈哈),比如上面的100個(gè)li,就要占用100個(gè)內(nèi)存空間,如果是1000個(gè),10000個(gè)呢,那只能說呵呵了,如果用事件委托,那么我們就可以只對(duì)它的父級(jí)(如果只有一個(gè)父級(jí))這一個(gè)對(duì)象
進(jìn)行操作,這樣我們就需要一個(gè)內(nèi)存空間就夠了,是不是省了很多,自然性能就會(huì)更好。
這句話讓我有一個(gè)深的體會(huì):原先認(rèn)為dom的操作,對(duì)domj節(jié)點(diǎn)的增刪改查,樣式的變化等內(nèi)容才會(huì)引起瀏覽器的重繪和重排,現(xiàn)在才知道給dom添加事件也會(huì)引起瀏覽器的重繪和重排.
寫的一個(gè)案例,可以執(zhí)行看看
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8" /> <title></title> <style> .login-header { width: 100%; text-align: center; height: 30px; font-size: 24px; line-height: 30px; } ul, li, ol, dl, dt, dd, div, p, span, h1, h2, h3, h4, h5, h6, a { padding: 0px; margin: 0px; } .login { width: 512px; height: 280px; position: absolute; left: 0; right: 0; border: #ebebeb solid 1px; background: #ffffff; box-shadow: 0px 0px 20px #ddd; z-index: 9999; display: none; /* overflow: hidden; */ } .login-title { width: 100%; margin: 10px 0px 0px 0px; text-align: center; line-height: 40px; height: 40px; font-size: 18px; position: relative; cursor: move; /* 火狐 */ -moz-user-select: none; /*webkit瀏覽器*/ -webkit-user-select: none; /*IE10*/ -ms-user-select: none; /*早期瀏覽器*/ -khtml-user-select: none; user-select: none; } .login-input-content { margin-top: 20px; } .login-button { width: 50%; margin: 30px auto 0px auto; line-height: 40px; font-size: 14px; border: #ebebeb 1px solid; text-align: center; } .login-bg { width: 100%; height: 100%; position: fixed; top: 0px; left: 0px; background: #000000; filter: alpha(opacity=30); opacity: 0.3; display: none; } a { text-decoration: none; color: #000000; } .login-button a { display: block; } .login-input input.list-input { float: left; line-height: 35px; height: 35px; width: 350px; border: #ebebeb 1px solid; text-indent: 5px; } .login-input { overflow: hidden; margin: 0px 0px 20px 0px; } .login-input label { float: left; width: 90px; padding-right: 10px; text-align: right; line-height: 35px; height: 35px; font-size: 14px; } .login-title span { position: absolute; font-size: 12px; right: -20px; top: -30px; background: #ffffff; border: #ebebeb solid 1px; width: 40px; height: 40px; border-radius: 20px; z-index: 99; cursor: pointer; } </style> </head> <body> <div class="login-header"> <a id="link" href="javascript:void(0);">點(diǎn)擊,彈出登錄框</a> </div> <div id="login" class="login"> <div id="title" class="login-title"> 登錄會(huì)員 <span id="closeBtn">關(guān)閉</span> </div> <div class="login-input-content"> <div class="login-input"> <label>用戶名:</label> <input type="text" placeholder="請(qǐng)輸入用戶名" name="info[username]" id="username" class="list-input" /> </div> <div class="login-input"> <label>登錄密碼:</label> <input type="password" placeholder="請(qǐng)輸入登錄密碼" name="info[password]" id="password" class="list-input" /> </div> </div> <div id="loginBtn" class="login-button"> <a href="javascript:void(0);" id="login-button-submit">登錄會(huì)員</a> </div> </div> <script> // 全部功能 let loginDom = document.querySelector(".login"); let linkDom = document.querySelector(".login-header a"); let closeBtn = document.querySelector("#closeBtn"); let userNameDom = document.querySelector("#username"); let passwordDom = document.querySelector("#password"); let winHeight = window.innerHeight; let winWidth = window.innerWidth; // API: 頁面的寬度和高度 => window.innerWidth window.innerHeight // 1. 顯示login的時(shí)候,讓login是水平垂直居中(left、top)不建議用css 會(huì)影響到拖拽 let originX = 0; let originY = 0; let logTop = 0; let logLeft = 0; linkDom.addEventListener("click", showFun); function showFun(e) { console.log("showFun"); e.stopPropagation(); loginDom.style.display = "block"; loginDom.style.top = (winHeight - loginDom.offsetHeight) / 2 + "px"; loginDom.style.left = (winWidth - loginDom.offsetWidth) / 2 + "px"; } closeBtn.addEventListener("click", closeFun); function closeFun(e) { loginDom.style.display = "none"; console.log("closeFun"); } document.addEventListener("click", closeFun); loginDom.addEventListener("mousedown", mouseDownFun); function mouseDownFun(e) { // e.stopPropagation(); console.log("mouseDownFun"); originX = e.pageX; originY = e.pageY; logLeft = this.offsetLeft; logTop = this.offsetTop; document.addEventListener("mousemove", mouseMoveFun); } function mouseMoveFun(e) { console.log("mouseMoveFun"); loginDom.style.left = e.pageX - originX + logLeft + "px"; loginDom.style.top = e.pageY - originY + logTop + "px"; } loginDom.addEventListener("click", logClickFun); // loginDom.addEventListener("dblclick", logClickFun); function logClickFun(e) { // e.stopPropagation(); console.log("logClickFun"); } loginDom.addEventListener("mouseup", mouseUpFun); function mouseUpFun(e) { e.stopPropagation(); console.log("mouseUpFun"); document.removeEventListener("mousemove", mouseMoveFun); } // userNameDom.addEventListener("focus", focusFun); userNameDom.addEventListener("click", userNameFun); function userNameFun(e) { e.stopPropagation(); console.log("userNameFun"); } // function focusFun(e) { // e.stopPropagation(); // console.log("blurFun"); // } // 2. 摁住title區(qū)域,實(shí)現(xiàn)拖拽效果 // 3. 限制login拖拽的范圍 // 4. 按住esc 鍵也能關(guān)閉掉 login // 5. 點(diǎn)擊頁面空白區(qū)域關(guān)閉也能關(guān)掉login </script> </body> </html>
阻斷冒泡是對(duì)同類事件起效果的
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <style> .father { width: 100px; height: 100px; background-color: red; } .son { width: 50px; height: 50px; background-color: yellow; } </style> </head> <body> <div class="father"> <div class="son"></div> </div> <script> let fatherDom = document.querySelector(".father"); let sonDom = document.querySelector(".son"); fatherDom.addEventListener("mousedown", fatherFun); function fatherFun(e) { alert("111111"); } sonDom.addEventListener("mousedown", sonFun); function sonFun(e) { e.stopPropagation(); alert("2222222222"); } </script> </body> </html>
參考資料:https://www.cnblogs.com/liugang-vip/p/5616484.html
聯(lián)系客服