JS事件详解和js事件委托

阅读 70

2022-02-07

简述事件

事件起始于IE3,作为一种分担服务器运算负载的一种手段。用于键盘、鼠标等工具对于网页的交互!事件对于不同浏览器来说,有不同的标准,尤其是IE、Chrome两大巨头浏览器上,虽然现如今Chrome已经占据大部分市场,但是对于IE8及以上的兼容也是个不小的问题。

事件类型

UI事件:用户与页面上的元素交互时触发;

焦点事件:当元素获取失去焦点是触发;

鼠标事件:当鼠标执行点击、移入移出或悬停等事件是触发;

滚轮事件:当鼠标、触摸板或其他设备滚动时触发滚动条事件;

文本事件:在文本框内输入文字时触发;

键盘事件:当键盘按下、抬起或点击时触发;

变动事件:当问文档结构发生变化时触发。

UI事件

load事件:当页面完全加载后再window上面触发,当所有框架都加载完成时,在框架集上面触发,当图片都加载完成时在img标签上面触发,或者当嵌入的内容加载完成时在object上触发。

unload事件:和load事件恰好相反,除img标签外,其他的框架和嵌入内容卸载完毕后在对应的级别上触发。

abort事件:在用户停止下载过程时,如果嵌入的内容没有加载完毕,在object元素上线触发。

error事件:当js发生语法错误时在window上触发,当发生加载图像无法成功时在img标签上触发,当嵌入的内容无法加载时在object元素上触发,或当一个或多个框架无法加载完成时在框架集上面触发。

select事件:当用户选择文本框内的文字时触发(input或textarea)。

resize事件:当窗口或者框架的大小变化时在window或框架上面触发。

scroll事件:当用户滚动带有滚动条的元素中的内容时,在该元素上面触发。body上就是网页自带的滚动条。

焦点事件

blur事件、focusout

输入框失去焦点事件,css有相同伪类选择器,但是不够灵活!

focusin事件、focus

输入框获取焦点是触发,前端培训讲解同样,css有相同的伪类事件。输入框如果使用 click同样能获取焦点,但是有点牛头马嘴的意思。

focus和blur事件不支持冒泡,如果不想文档事件冒泡则使用这两个事件更好,不用屏蔽事件流。

鼠标与滚轮事件

mousedown、mouseup事件

鼠标左键按下、抬起事件,相继触发这两个事件后还会触发click事件。

click事件、dbclick事件

鼠标单击、双击事件

mouseleave、mouseout事件

都是鼠标脱离当前区域触发,不同的是mouseleave不冒泡。

mouseenter、mouseover事件

鼠标进入、悬停在当前区域时触发,mouseenter事件不冒泡。

mousemove事件

当鼠标在当前区域移动时重复触发!

mousewheel事件

滚轮事件在鼠标中间滚动时触发,同时包含一个wheelData属性,它是120的整数倍数,滚轮向上滚动一个单位时wheelDate+120,向下滚动时-120,。

键盘与文本事件

keydown:当用户按下键盘等按键设备上的按钮时触发,按住不放会重复触发。

keyup、keypress:按键按下后释放时触发。两个事件都是同时触发keyCode的值,但是keypress会输出input框的上一个值,而keyup会立即输出当前input的值。如下:<body>

在我依次按下数字键1、2、3、4、5、6时控制台是如下效果:

但是如果是keyup的事件呢:

在我依次按下数字键1、2、3、4、5、6时控制台是如下效果:

事件流

事件流描述的是事件在网页文档中的接收顺序,它描述着事件发生时,事件是顺着文档流向上还是向下!

但是奇趣的是,IE和Netscape开发团队提出了两个完全相反的事件流概念!那就是事件冒泡和事件捕获!

根据网页文档的DOM级别规定层级结构:

文档结构documenthtmlbodyelement

事件冒泡

假定事件在element上触发,然后事件会跟着下图一次冒泡

事件是默认冒泡的,在IE9,Opera9.5及其他浏览器各版本及更高版本都是支持事件流的,但是上述明确浏览器的更低版本则不支持。

控制台输出的结果:

如果我们把this全价格toString方法改为字符串!

事件捕获

同事件冒泡正好相反,它会按照事件流向下级结构传递:

而控制他们事件流传递方向的创建事件监听时的一个参数,后面我再详细解释。

创建和移除事件监听

创建事件监听addEventListener()方法

它的第三个参数默认为false,代表默认使用事件冒泡规则,同时事件会根据冒泡规则一次向上传递,如果改为true则事件采用事件捕获规则,根据文档结构和元素关系进行事件的向下传递。

事件的移除removeEventListener()方法

没错,remove里的没有执行,但是add里的却仍然很好的执行了!那我们来看正确的方式!

究其原因,是因为上面的创建和移除是各自创建的函数,它们看起来很像,但是根本没有丝毫”血缘”关系,它们在内存中占据了两个不同的位置,而后面引用的函数名确实代表的同一个”东西”,它们指向的是内存中的同一个位置!!!

阻止事件的冒泡或者捕获、默认行为

阻止事件流的传递,stopPropagation()方法,为了方便我这里不用规范的创建监听方法了:

如果要测试事件捕获需要用规范的创建事件监听,并使第三个参数改为true就可以了!

阻止默认行为发生

说到默认行为,就像a标签点击了会默认跳转到href一样,那么我们可以通过使用preventdefault()方法实现,但是前提条件是对象的属性cancelable属性必须设置为true才可以阻止该对象的默认行为,使用时同时用event对象来调用!大家可以自行测试,这里就不赘述了。

事件委托

内存和性能:在一门编程语言中,给一个控件或者目标添加看似是司空见惯的事,但是却有着非比寻常的。在包含GUI编程的语言里,给每一个控件添加事件都是没有问题的,因为它编译的时候有一些特殊的事情要做,像我学过的C#/.NET中就是这样,不过js和众多桌面语言中有着很大的却别,因为js是个单线程的语言,不能像桌面语言那样new Thread()来继续做自己的事,而是必须等待!事件在整个编译运行过程中也是遵循排队等待的铁则!那么精简的事件监听程序则是一个js脚本是否性能良好的体现!

跨浏览器的事件监听程序

说起来高大上,说实在的就是因为浏览器对事件监听程序创建的差异,谷歌是addEventListener(),IE 是attachEvent(),或者其他浏览器支持用οnclick=handler(以点击事件为例)创建,而对于事件,谷歌可以直接用click,而IE就必须用onclick等等,为了js程序能在不同浏览器都能跑起来,所以,一个整合的跨浏览器的事件监听创建程序非常必要!毕竟还有有很多不会升级电脑和软件的朋友存在,尤其那些还在用xp系统的办公电脑啊。。。

什么是事件委托?

刚才我有提到,js本就是一个简单的脚本语言,没有桌面编程语言的多线程,所以每一个对象都创建一个甚至多个事件监听是非常耗费性能的!那么我们怎么解决呢?就是事件委托,事件委托的中心思想就是,我给当前模块尽可能给最大的父级创建事件监听程序,然后通过父级对子级进行事件的分发,对子级拥有对应功能的事件进行响应!形象化就像是一个酒店的服务台,一个服务台发送一个点击事件,服务台将事件分发到需要触发该事件的对应房间,因为js的单线程机制,所有消息和事件都是在队列中排队的,所以没有“占线”这一说法!所有的事件都能正常地分发给对应目标,从而省下很多性能资源!

实现以下委托:

这里我把键盘事件放在document上,是为了键盘能在全局被监听到,使用时并不是对象越大越好,一般来说模块化里同一个子父级树里尽量按照更高的父级关系设置是最好的!

精彩评论(0)

0 0 举报