JavaScript事件机制——记一次认真准备的技术分享
先问几个问题,你是否能快速闪过答案?
- 自下而上(冒泡)事件怎么写,自上而下(捕获)又是怎么写?
- 捕获型和冒泡型同时存在,谁生效?
- jquery的on或bind是冒泡,还是捕获?
- 冒泡能够阻止,那捕获能够阻止吗?
- stopPropagation 和 stopImmediatePropagation的区别
- Event.bubbles,Event.eventPhase
- Event.cancelable,Event.cancelBubble,event.defaultPrevented
- 常用技巧
js事件的捕获和冒泡图
举个例子:
点击s2,s1分别会打印什么?
<div id="s1">s1 <div id="s2">s2</div> </div> <script> s1.addEventListener("click",function(e){ console.log("s1 冒泡事件"); },false); s2.addEventListener("click",function(e){ console.log("s2 冒泡事件");},false); s1.addEventListener("click",function(e){ console.log("s1 捕获事件");},true); s2.addEventListener("click",function(e){ console.log("s2 捕获事件");},true); </script> //s1 捕获事件 //s2 冒泡事件 //s2 捕获事件 //s1 冒泡事件
点击s2,click事件从document->html->body->s1->s2(捕获前进)这里在s1上发现了捕获注册事件,则输出"s1 捕获事件"到达s2,已经到达目的节点。
s2上注册了冒泡和捕获事件,先注册的冒泡后注册的捕获,则先执行冒泡,输出"s2 冒泡事件"
再在s2上执行后注册的事件,即捕获事件,输出"s2 捕获事件"
下面进入冒泡阶段,按照s2->s1->body->html->documen(冒泡前进) 在s1上发现了冒泡事件,则输出"s1 冒泡事件"
jQuery的on事件是冒泡
下面贴上jquery的on事件的源码
常用技巧
onclick -->事件冒泡,重写onlick会覆盖之前属性,没有兼容性问题
ele.onclik = null; //解绑单击事件,将onlick属性设为null即可 复制代码
阻止默认事件(href=""链接,submit表单提交等)
-
return false; 阻止独享属性(通过on这种方式)绑定的事件的默认事件
ele.onclick = function() { …… //你的代码 return false; //通过返回false值阻止默认事件行为 } 复制代码
但是,在jQuery中,我们常用return false来阻止浏览器的默认行为,那”return false“到底做了什么? 当你每次调用”return false“的时候,它实际上做了3件事情:
-
event.preventDefault();
-
event.stopPropagation();
-
停止回调函数执行并立即返回。
这3件事中用来阻止浏览器继续执行默认行为的只有preventDefault,除非你想要停止事件冒泡,否则使用return false会为你的代码埋下很大的隐患。
-
element.addEventListener(“click”, function(e){ var event = e || window.event; …… event.preventDefault( ); //阻止默认事件 },false);
event.returnValue = false; 阻止通过 attachEvent( ) 添加的事件的默认事件(此事件为ie浏览器特有)
element.attachEvent(“onclick”, function(e){ var event = e || window.event; …… event.returnValue = false; //阻止默认事件 },false);
把事件绑定以及事件解绑封装成为一个函数,兼容浏览器,包括IE6及以上(虽然现在基本上都放弃了IE9以下了hhhh)
// 事件绑定 function addEvent(element, eType, handle, bol) { if(element.addEventListener){ //如果支持addEventListener element.addEventListener(eType, handle, bol); }else if(element.attachEvent){ //如果支持attachEvent element.attachEvent("on"+eType, handle); }else{ //否则使用兼容的onclick绑定 element["on"+eType] = handle; } } // 事件解绑 function removeEvent(element, eType, handle, bol) { if(element.addEventListener){ element.removeEventListener(eType, handle, bol); }else if(element.attachEvent){ element.detachEvent("on"+eType, handle); }else{ element["on"+eType] = null; } }
事件停止传播 stopPropagation 和 stopImmediatePropagation
// 事件传播到 element 元素后,就不再向下传播了 element.addEventListener('click', function (event) { event.stopPropagation(); }, true); // 事件冒泡到 element 元素后,就不再向上冒泡了 element.addEventListener('click', function (event) { event.stopPropagation(); }, false);
但是,stopPropagation方法只会阻止 【该元素的当前事件(冒泡或者捕获)】 的传播,不会阻止该节点的其他click事件的监听函数。也就是说,不是彻底取消click事件,它还可以正常创建一个新的click事件。
element.addEventListener('click', function (event) { event.stopPropagation(); console.log(1); }); element.addEventListener('click', function(event) { // 会触发 console.log(2); });
element.addEventListener('click', function (event) { // 会触发 console.log(‘改方法内的可以执行’); event.stopImmediatePropagation(); // 会触发 console.log(1); }); element.addEventListener('click', function(event) { // 不会被触发 console.log(2); }); // Jquery同理 $(element).click(function() { // 不会触发 console.log(‘jquery click’) }) $(element).hover(function() { // 会触发 console.log(‘jquery click’) })
Event.bubbles,Event.eventPhase
Event.bubbles属性返回一个布尔值,表示当前事件是否会冒泡。该属性为只读属性,一般用来了解 Event 实例是否可以冒泡。前面说过,除非显式声明,Event构造函数生成的事件,默认是不冒泡的。可以根据下面的代码来判断事件是否冒泡,从而执行不同的函数。
function goInput(e) { if (!e.bubbles) { passItOn(e); } else { doOutput(e); } }
专门查了一下不支持冒泡的事件有:
- UI事件(load, unload, scroll, resize)
- 焦点事件(blur, focus)
- 鼠标事件(mouseleave, mouseenter)
Event.eventPhase属性返回一个整数常量,表示事件目前所处的阶段。该属性只读。
var phase = event.eventPhase; 复制代码
Event.eventPhase的返回值有四种可能。
- 0,事件目前没有发生。
- 1,事件目前处于捕获阶段,即处于从祖先节点向目标节点的传播过程中。
- 2,事件到达目标节点,即Event.target属性指向的那个节点。
- 3,事件处于冒泡阶段,即处于从目标节点向祖先节点的反向传播过程中。
Event.cancelable,Event.cancelBubble,event.defaultPrevented
Event.cancelable属性返回一个布尔值,表示事件是否可以取消。该属性为只读属性,一般用来了解 Event 实例的特性。
大多数浏览器的原生事件是可以取消的。比如,取消click事件,点击链接将无效。但是除非显式声明,Event构造函数生成的事件,默认是不可以取消的。
var evt = new Event('foo'); evt.cancelable // false 复制代码
当Event.cancelable属性为true时,调用Event.preventDefault()就可以取消这个事件,阻止浏览器对该事件的默认行为。 注意,该方法只是取消事件对当前元素的默认影响,不会阻止事件的传播。如果要阻止传播,可以使用stopPropagation()或stopImmediatePropagation()方法。
function preventEvent(event) { if (event.cancelable) { event.preventDefault(); } else { console.warn('This event couldn\'t be canceled.'); console.dir(event); } }
Event.cancelBubble属性是一个布尔值,该属性可以自行设置。如果设为true,相当于执行Event.stopPropagation(),可以阻止事件的传播。
注意:MDN里说该特性已经从 Web 标准中删除,虽然一些浏览器目前仍然支持它,但也许会在未来的某个时间停止支持,请尽量不要使用该特性。请使用 event.stopPropagation() 方法来代替该不标准的属性.cancelBubble-MDN
Event.defaultPrevented属性返回一个布尔值,表示该事件是否调用过Event.preventDefault方法。该属性只读。
if (event.defaultPrevented) { console.log('该事件已经取消了'); }
主要参考文档:
原文作者:闲淡超人
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
vue-router 源码:前端路由
前言 在学习 vue-router 的代码之前,先来简单了解一下前端路由。 前端路由主要有两种实现方法: Hash 路由 History 路由 先来看看这两种方法的实现原理。 接着我们将用它们来简单实现一个自己的前端路由。 前端路由 Hash 路由 url 的 hash 是以 # 开头,原本是用来作为锚点,从而定位到页面的特定区域。当 hash 改变时,页面不会因此刷新,浏览器也不会向服务器发送请求。 http://www.xxx.com/#/home 同时,hash 改变时,并会触发相应的 hashchange 事件。所以,hash 很适合被用来做前端路由。当 hash 路由发生了跳转,便会触发 hashchange 回调,回调里可以实现页面更新的操作,从而达到跳转页面的效果。 window.addEventListener('hashchange', function () { console.log('render'); }); History 路由 HTML5 规范中提供了 history.pushState 和 history.replaceState 来进行路由控制。通过这...
- 下一篇
【JSConf EU 2018】Rust + WebAssembly
欧洲JSConf上的神秘项目 在今年的欧洲JSConf上来自Mozilla的Lin Clark为我们展示一个神秘项目,一个的拱形彩虹门(视频传送门),它实际上是由三万个彩色LED组成的画布,可以展现灯光动画,并且通过Rust编写的WebAssembly模块来控制“拱门”的灯光动画。Lin在2017年的JSConf上也曾做过关于WebAssembly的演讲,在该演讲中她提到2008年是JavaScript执行效率曲线的一个拐点,随着众多浏览器加入了JIT编译器(Just-in-time compiler),JavaScript的运行性能带来了十倍的增速,这为JavaScript插上了一双翅膀使它可以自由翱翔在浏览器端、服务器端和客户端。Lin指出WebAssembly的诞生可能会成为曲线的下一个拐点。可见Mozilla对WebAssembly的重视程度。 emm...让我们回到2018年。Lin在会上说明了如何使用WebAssembly模块控制“拱门”的灯光动画。下面让我们来看下这是如何做到的。 用字节把空间或时间连续起来 我们所处的空间是一个三维空间,如果再给它加上时间维度,那它就是四...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- Mario游戏-低调大师作品
- CentOS6,CentOS7官方镜像安装Oracle11G
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- Windows10,CentOS7,CentOS8安装Nodejs环境
- Docker安装Oracle12C,快速搭建Oracle学习环境
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- CentOS8编译安装MySQL8.0.19
- MySQL8.0.19开启GTID主从同步CentOS8
- CentOS8安装Docker,最新的服务器搭配容器使用