先来上一段个人总结的理解
1/事件分为三个部分
(1)捕获阶段
(2)目标阶段
(3)冒泡阶段
事件冒泡
1/阻止事件冒泡是对同类名事件而言 (为什么得出这个结论呢: 在父元素和子元素 写的事件都不一样,mousedown ,mouseup , mouseove ,fouce,blur 都尝试写了阻断,当时都没发阻止最上面的onclick的事件发生页面最后又案例.,后续又试验了给父元素和子元素都只添加mousedown,发现阻断是有效的,后面有案例 )
2/事件冒泡的形象图:
请注意一点:默认是冒泡的,若是变捕获,需要改变addEventListener的第三个值
(1):false 默认值 冒泡
(2):true 不冒泡 捕获
事件对象:事件特有的对象,e 是变量名,常用的名字,可以为任何名字
document.onclick = functionl(e){ //e 可以为任何名字,建议用e //e有内容 常见的有 // e.target 目标 //e.type 事件类型 ..... //当点击的内容是document本身,那么e.target === this //true //当点击的内容是它内部的div元素,那么e.target ===this //false }
//事件委托
什么是委托?
语言的含义: 我把一些感觉可以让别人帮忙处理的问题委托给别人处理.
在此处在举一个例子: 公司前台MM收快递
那什么叫事件委托呢?它还有一个名字叫事件代理,JavaScript高级程序设计上讲:事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。那这是什么意思呢?网上的各位大牛们讲事件委托基本上都用了同一个例子,就是取快递来解释这个现象,我仔细揣摩了一下,这个例子
还真是恰当,我就不去想别的例子来解释了,借花献佛,我摘过来,大家认真领会一下事件委托到底是一个什么原理: 有三个同事预计会在周一收到快递。为签收快递,有两种办法:一是三个人在公司门口等快递;二是委托给前台MM代为签收。现实当中,我们大都采用委托的方案(公司也不会容忍那么多员工站在门口就为了等快递)。前台MM收到快递后,她会判断收件人是谁,然后按照收件人的要求签收,甚至代为付款。
这种方案还有一个优势,那就是即使公司里来了新员工(不管多少),前台MM也会在收到寄给新员工的快递后核实并代为签收。 这里其实还有2层意思的: 第一,现在委托前台的同事是可以代为签收的,即程序中的现有的dom节点是有事件的; 第二,新员工也是可以被前台MM代为签收的,即程序中新添加的dom节点也是有事件的。
第二个点让我联想思考了冒泡事件的第二个阶段
事件委托的原理(主要理解target属性)::
就是利用事件冒泡原理(请先理解冒泡),然后通过target属性,返回事件的目标节点,称为事件源,可以理解为target是实际点击的哪个标签(dom),但不是实际的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);
}
}
}
借鉴别人的代码,真的很经典,点个赞
为什么要用事件委托?
一般来说,dom需要有事件处理程序,我们都会直接给它设事件处理程序就好了,那如果是很多的dom需要添加事件处理呢?比如我们有100个li,每个li都有相同的click点击事件,可能我们会用for循环的方法,来遍历所有的li,然后给它们添加事件,那这么做会存在什么影响呢? 在JavaScript中,添加到页面上的事件处理程序数量将直接关系到页面的整体运行性能,因为需要不断的与dom节点进行交互,访问dom的次数越多,引起浏览器重绘与重排的次数也就越多,就会延长整个页面的交互就绪时间,这就是为什么性能优化的主要思想之一就是减少DOM操作的原因;如果要用事件委托,
就会将所有的操作放到js程序里面,与dom的操作就只需要交互一次,这样就能大大的减少与dom的交互次数,提高性能; 每个函数都是一个对象,是对象就会占用内存,对象越多,内存占用率就越大,自然性能就越差了(内存不够用,是硬伤,哈哈),比如上面的100个li,就要占用100个内存空间,如果是1000个,10000个呢,那只能说呵呵了,如果用事件委托,那么我们就可以只对它的父级(如果只有一个父级)这一个对象
进行操作,这样我们就需要一个内存空间就够了,是不是省了很多,自然性能就会更好。
这句话让我有一个深的体会:原先认为dom的操作,对domj节点的增删改查,样式的变化等内容才会引起浏览器的重绘和重排,现在才知道给dom添加事件也会引起浏览器的重绘和重排.
写的一个案例,可以执行看看
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8" /> <title></title> <style> .login-header { 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 { 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 { 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 { 50%; margin: 30px auto 0px auto; line-height: 40px; font-size: 14px; border: #ebebeb 1px solid; text-align: center; } .login-bg { 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; 350px; border: #ebebeb 1px solid; text-indent: 5px; } .login-input { overflow: hidden; margin: 0px 0px 20px 0px; } .login-input label { float: left; 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; 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);">点击,弹出登录框</a> </div> <div id="login" class="login"> <div id="title" class="login-title"> 登录会员 <span id="closeBtn">关闭</span> </div> <div class="login-input-content"> <div class="login-input"> <label>用户名:</label> <input type="text" placeholder="请输入用户名" name="info[username]" id="username" class="list-input" /> </div> <div class="login-input"> <label>登录密码:</label> <input type="password" placeholder="请输入登录密码" 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">登录会员</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的时候,让login是水平垂直居中(left、top)不建议用css 会影响到拖拽 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区域,实现拖拽效果 // 3. 限制login拖拽的范围 // 4. 按住esc 键也能关闭掉 login // 5. 点击页面空白区域关闭也能关掉login </script> </body> </html>
阻断冒泡是对同类事件起效果的
<!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 { 100px; height: 100px; background-color: red; } .son { 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