一、名称解释1、事件事件是文档或者浏览器窗口中发生的,特定的交互瞬间。事件是用户或浏览器自身执行的某种动作,如click,load和mouseover等事件。事件是javaScript和DOM之间交互的桥梁。2、事件流事件发生时会在元素节点与根节点之间按照特定的顺序传播,路径所经过的所有节点都会收到该事件,这个传播过程即DOM事件流。事件流包括三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段3、事件流模型事件传播的顺序对应浏览器的两种事件流模型:捕获型事件流和冒泡型事件流。冒泡型事件流:事件的传播是从最特定的事件目标到最不特定的事件目标。即从DOM树的叶子到根。捕获型事件流:事件的传播是从最不特定的事件目标到最特定的事件目标。即从DOM树的根到叶子。
图片
ps. 事件捕获阶段:实际目标(<div>)在捕获阶段不会接收事件。也就是在捕获阶段,事件从document到<html>再到<body>就停止了。上图中为1~3.处于目标阶段:事件在<div>上发生并处理。但是事件处理会被看成是冒泡阶段的一部分。冒泡阶段:事件又传播回文档。二、事件冒泡 vs 事件捕获事件冒泡 和 事件捕获 分别由 微软 和 网景 公司提出,后来 W3C 将两者结合,制定了统一的标准 —— 先捕获再冒泡。在 JavaScript 中,addEventListener 方法用于向指定元素添加事件句柄。语法:element.addEventListener(event, function, useCapture)
图片
1、事件冒泡来看一段代码实例,思考运行后会打印出什么。
图片

图片
根据冒泡事件流模型由内向外的规则,会依次弹出:click div -> click body -> click html -> click docuement2、事件捕获将上一段代码中的 false 都改为 ture,则变为捕获方式:
图片

图片
根据捕获事件流模型由外向内的规则,会依次弹出:click document -> click html -> click body -> click div3、事件冒泡&事件捕获同时存在如果两种事件流模型同时存在会怎样展示呢?
图片

图片
原则:a.从外向内,捕获前进,遇到捕获事件立即执行b.非 target 节点,先捕获再冒泡c.target 节点,按代码书写顺序执行(无论冒泡还是捕获)因此会依次弹出:click document -> click html -> click div -> click body4、阻止冒泡的方法----event.stopPropagation()方法 这是阻止事件的冒泡方法,不让事件向document上蔓延,但是默认事件仍然会执行,当你调用这个方法的时候,如果点击一个连接,这个连接仍然会被打开。5、阻止默认事件的方法---event.preventDefault()方法这是阻止默认事件的方法,调用此方法是,连接不会被打开,但是会发生冒泡,冒泡会传递到上一层的父元素。举个栗子:看图说话,在下面的空白处,无论我怎么点击右键,无论在什么位置点击,都会出现默认框。
图片
如果我们不想要这种默认的框怎么办呢?
图片

图片
6、return false这个方法比较暴力,他会同时阻止事件冒泡也会阻止默认事件;写上此代码,链接不会被打开,事件也不会传递到上一层的父元素;可以理解为return false就等于同时调用了event.stopPropagation()和event.preventDefault()三、事件委托1.什么是事件委托?事件委托又名事件代理,JavaScript高级程序设计上讲:事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。举个栗子:班级收作业收作业有两种方法:一是谁写完了自己去交个老师。二是写完了统一交给班长,让班长交给老师,现实当中,我们大都采用第二种方法。这就可以理解为委托,无论是谁交给老师,目的只有一个就是作业能够正常上交。2.为什么要用委托?一般来说,dom需要有事件处理程序,我们都会直接给它设事件处理程序就好了,那如果是很多的dom需要添加事件处理呢?比如我们有100个li,每个li都有相同的click点击事件,可能我们会用for循环的方法,来遍历所有的li,然后给它们添加事件,那这么做会存在什么影响呢?在JavaScript中,添加到页面上的事件处理程序数量将直接关系到页面的整体运行性能,因为需要不断的与dom节点进行交互,访问dom的次数越多,引起浏览器重绘与重排的次数也就越多,就会延长整个页面的交互就绪时间,这就是为什么性能优化的主要思想之一就是减少DOM操作的原因;如果要用事件委托,就会将所有的操作放到js程序里面,与dom的操作就只需要交互一次,这样就能大大的减少与dom的交互次数,提高性能;每个函数都是一个对象,是对象就会占用内存,对象越多,内存占用率就越大,自然性能就越差了。比如上面的100个li,就要占用100个内存空间,如果是1000个,10000个呢,如果用事件委托,那么我们就可以只对它的父级(如果只有一个父级)这一个对象进行操作,这样我们就需要一个内存空间就够了,是不是省了很多,自然性能就会更好。3.事件委托原理事件委托是利用事件的冒泡原理来实现的,何为事件冒泡呢?就是事件从最深的节点开始,然后逐步向上传播事件,举个栗子:页面上有这么一个节点树,div>ul>li>a;比如给最里面的a加一个click点击事件,那么这个事件就会一层一层的往外执行,执行顺序a>li>ul>div,有这样一个机制,那么我们给最外面的div加点击事件,那么里面的ul,li,a做点击事件的时候,都会冒泡到最外层的div上,所以都会触发,这就是事件委托,委托它们父级代为执行事件。4.事件委托怎么实现?
图片

图片
当用事件委托的时候,根本就不需要去遍历元素的子节点,只需要给父级元素添加事件就好了,其他的都是在js里面的执行,这样可以大大的减少dom操作。5.总结那什么样的事件可以用事件委托,什么样的事件不可以用呢?适合用事件委托的事件:click,mousedown,mouseup,keydown,keyup,keypress。值得注意的是,mouseover和mouseout虽然也有事件冒泡,但是处理它们的时候需要特别的注意,因为需要经常计算它们的位置,处理起来不太容易。不适合的就有很多了,举个例子,mousemove,每次都要计算它的位置,非常不好把控,在不如说focus,blur之类的,本身就没用冒泡的特性,自然就不能用事件委托了。


纷橙
13 声望1 粉丝