DOM事件,事件委托
1.什么是事件
事件就是一件事情或者一个行为(对于元素来说,它的很多事件都是天生自带的),只要我们去操作这个元素,就会触发这些行为,
事件就是元素天生自带的行为,我们操作元素,就会触发相关的事件行为
2.事件绑定
给元素天生自带的事件行为绑定方法,当事件触发,会把对应的方法执行
元素.οnclick=function(){}
3.元素天生自带的事件
3.1.鼠标事件
-
click:点击事件(PC端是点击,移动端的click代表点击【移动端使用click会有300ms延迟的问题】)
-
dblclick:双击事件
-
mouseover:鼠标经过
-
mouseout:鼠标移出
-
mouseenter:鼠标进入
-
mouseleave:鼠标离开
-
mousemove:鼠标移动
-
mousedown:鼠标按下(鼠标左右键都起作用,它是按下即触发,click是按下抬起才会触发,而且是先把down和up触发,才会触发click)
-
mouseup:鼠标抬起
-
mousewheel:鼠标滚轮滚动
3.2.键盘事件
-
keydown:键盘按下
-
keyup:键盘抬起
-
keypress:和keydown类似,只不过keydown返回的是键盘码,keypress返回的是ASCII码
-
input:由于PC端有实体物理键盘,可以监听到键盘的按下和抬起,但是移动端是虚拟键盘,所有keydown和keyup在大部分手机上都没有,我们使用input事件统一替他们(内容改变事件)
3.3.表单元素常用事件
-
focus:获取焦点
-
blur:失去焦点
-
change:内容改变
3.4.其它常用事件
-
load:加载完成
-
unload:当文档或一个子资源正在被卸载时, 触发 unload事件
-
beforeunload:在卸载之前触发
-
scroll:滚动条滚动事件
-
resize:大小改变事件 window.οnresize=function(){}当浏览器窗口大小发生改变,会触发这个事件,执行对应的事件
3.5.移动端手指事件
-
touch:单手指操作
-
touchstart:手指按下
-
touchmove:手指移动
-
touchend:手指离开
-
touchcancel:因为意外情况导致手指操作取消
-
-
gesture:多手指操作
-
gesturestart:手指按下
-
gesturechange:手指改变
-
gestureend:手指离开
-
3.6.H5中的audio/video音视频事件
-
canplay:可以播放(播放过程中可能出现由于资源没有加载完成,导致的卡顿)
-
canplaythrough:资源加载完成,可以正常无障碍播放
4.事件绑定机制
4.1.不同的绑定方式
-
DOM0级事件绑定
[element].onxxx=function(){}
-
DOM2级事件绑定
[element].addEventListener('xxx',function(){},false) //[IE6~8] [element].attachEvent('onxxx',function(){})
目的:给当前元素的某个事件绑定方法(不管是基于DOM0还是DOM2),都是为了触发元素的相关行为的时候,能做点事情(也就是把绑定的方法执行);
不仅把方法执行了,而且浏览器还给方法传递了一个实参信息值,这个值就是事件对象
4.2.形参event
-
定义一个形参e用来接收方法执行的时候浏览器传递的信息值(事件对象:
MouseEvent
鼠标事件对象,KeyboardEvent
键盘事件对象,Event
普通事件对象) -
事件对象中记录了很多属性名和属性值,这些信息中包含了前面操作的基本信息,例如:鼠标点击位置的X/Y轴坐标,鼠标点击的是谁(事件源)等信息
元素.οnclick=function(e){ }
4.3.MouseEvent(鼠标事件对象)
-
event.target:事件源(操作的是哪个元素)
-
event.clientX /event.clientY:当前鼠标触发点距离当前窗口最上角的X/Y轴坐标
-
event.pageX/event.pageY:当前鼠标触发点距离body(第一屏幕)左上角的X/Y轴坐标
-
event.preventDefault():阻止默认行为
-
event.type:当前事件类型(click,mouseenter...)
container.οnclick=function(e){ console.log(e); }
4.4.KeyboardEvent(键盘事件对象)
当在键盘上按下a时
-
event.code:当前按键
keyA
-
event.key:当前按键
a
-
event.which/event.keyCode:当前按键的键盘
65
input.οnkeydοwn=function(e){ console.log(e); }
常用的键盘码:
-
左,上,右,下:37,38 , 39 , 40
-
backspace:8
-
enter:13
-
space:32
-
delete:46
-
shift:16
-
alt:18
-
ctrl:17
-
esc:27
-
f1~f12:112-123
-
48-57:数字键
-
65-90:小写字母
4.5.DOM0
每个元素对象都是对应类的实例,浏览器天生为其设置了很多私有属性和公有的属性方法,而onclick就是其中的一个私有属性(事件类私有属性,还有很多其它的事件私有属性),这些属性默认值是Null
DOM0事件绑定的原理:
就是给元素的某一个事件私有属性赋值(浏览器会建立监听机制,当我们触发元素的某个行为,浏览器会自己把属性中赋的值去执行)
DOM0事件绑定:只允许给当前元素的某个事件行为绑定一个方法,多次绑定,后面绑定的内容会替换前面绑定的,以最后一次绑定的方法为主
4.6.DOM2
addEventListener,removeEventListener都是EventTarget.prototype定义的,在IE低版本中使用的是attachEvent来处理的,移除使用的是dettachEvent,DOM2事件绑定可以给当前元素的某一个事件行为绑定
多个不同的方法
DOM2事件绑定兼容:
-
谷歌 VS IE高版本:
-
在移除事件绑定的时候,如果移除操作发生在正要执行的方法之前(例如:点击的时候,正要执行FN8,但是在执行FN4的时候,我们把FN8从事件池中移除了),谷歌下是立即移除生效,第一次也不再执行FN8了,而IE是当前本次不生效,下一次点击才生效,第一次点击还是要执行FN8的;
-
-
标准 VS IE低版本:
-
标准:addEventListener / removeEventListener IE低:attachEvent / detachEvent
-
THIS问题 标准浏览器中,行为触发方法执行,方法中的THIS是当前元素本身,IE低版本中THIS指向了WINDOW
-
重复问题 标准浏览器中的事件池是默认去重复的,同一个元素的同一个事件行为不能出现相同的绑定方法,但是IE低版本的事件池机制没有这么完善,不能默认去重,也就是可以给同个元素的同个事件绑定相同的方法了
-
顺序问题 标准浏览器是按照向事件池中存放的顺序依次执行的,而IE低版本是乱序执行的,没有规律
-
IE低版本浏览器出现的所有问题都是由于本身自带的事件池机制不完整导致的
-
4.7.DOM0事件绑定和DOM2事件绑定区别
-
机制不一样
-
DOM0采用的是给私有属性赋值,所以只能绑定一次方法
-
DOM2采用的是事件池机制,所以能绑定多个不同的方法
-
-
移除的操作
-
DOM2事件绑定中增加了一些DOM0无法操作的事件行为,例如:DOMContentLoaded事件(当页面中的HTML结构加载完成就会触发执行)
window.οnlοad=function(){ //=>当前页面中的资源都加载完成(HTML,CSS,JS)才会触发执行 } window.addEventListener('load',function(){ //=>当页面中的HTML结构加载完成就会执行 }) //=>$(document).ready(function(){}) //原理:基于DOMContentLoaded完成的(IE中用的是onreadystatechange监听的,在document.readyState === "complete"时候执行函数) $(function () { //=>当页面中的HTML结构加载完成就会执行 }); $(function(){ //=>基于DOM2事件绑定的,所以在同一个页面中可以执行多次(绑定多个不同的方法),当结构加载完成,会依次执行这些方法 });
5.兼容低版本浏览器
-
在IE低版本浏览器中,浏览器执行绑定的方法,并没有把事件对象传递进来,此时event=undefined.需要基于window.event来获取(由于是全局属性,鼠标每次操作都会把上一次操作的值起换掉)
container.οnclick=function(e){ if(!e){ e=window.event //=>e.srcElement是获取事件源,标准浏览器中使用e.target e.target=e.srcElement //=>低版本浏览器的事件对象中不存在pageX/pageY e.pageX=e.clientX+(document.documentElement.scrollLeft || document.body.scrollLeft) e.pageY=e.clientY+(document.documentElement.scrollTo || document.body.scrollTo) e.which=e.keyCode //preventDefault & stopPropagation低版本下都没有 e.preventDefault=function(){ e.returnValue=false } e.stopPropagation=function(){ e.cancelBubble=true } } //=>直接按高版本 }
6.事件默认行为
事件本身就是天生就有的,某些事件触发,即使你没有绑定方法,也会存在一些效果,这些默认的效果就是
事件默认行为
6.1.a标签默认行为
-
页面跳转
-
锚点定位(hash定位【哈西定位】)
<a href="http://www.baidu.com" target="_blank">百度</a>
target="_blank":在新窗口打卡
<a href="#box">位置</a>
首先会在当前页面url地址栏末尾设置一个hash值,浏览器检测到hash值后,会默认定位到当前页面中ID和hash相同的盒子的位置(基于hash值我们还可以实现spa单页面应用)
6.2.input默认行为
-
输入内容可以呈现到文本框中
-
输入内容的时候会把之前输入的一些信息呈现出来(并不是所有浏览器和所有情况下都有)
6.3.submit按钮默认行为
-
点击按钮页面会刷新
<form action='http://www.baidu.com'> <input type='submit' value='提交'/> </form>
在form中设置action,点击submit,会默认按照action指定的地址进行页面跳转,并且把表单中信息传递过去(非前后端分离项目中,有服务器进行页面渲染)
7.阻止事件默认性
7.1.阻止a默认行为
//javascript:void 0/undefined/null...; <a href="javascript:;">百度</a>
7.2.在JS中阻止默认行为
box.οnclick=function(e){ e=e || window.event e.preventDefault ? e.preventDefault() : e.returnValue=false }
7.3.案例
最多输入6位
inputHandler.οnkeydοwn=function(e){ e=e || window.event let value=this.value.trim(),//trim不兼容 len=value.length if(len>=6){ this.value=value.substr(0,6) let code=e.which || e.keyCode if(!/^(46|8|37|38|39|40)$/.test(code)){ e.preventDefault ? e.preventDefault() : e.returnValue=false } } }
8.事件的传播机制
冒泡传播:触发当前元素的某一个事件(点击事件)行为,不仅当前元素事件行为触发,而且其祖先元素的相关事件行为也会一次被触发,这种机制就是
事件的冒泡传播机制
8.1.不同浏览器
不同浏览器对于最外层祖先元素定义是不一样的
-
谷歌:window->document->html->body...
-
IE高版本:window->html->body...
-
IE低:html->body...
8.2.理解
-
事件对象是用来储存当前本次操作的相关信息,和操作有关,和元素无必然联系
-
当我们基于鼠标或键盘操作的时候,浏览器会把本次操作的信息存储起来(标准流量拿起存储到默认的内存中(自己找不到),IE低版本存储到window.event中),存储的值是一个对象(堆内存);操作肯定会触发元素的某个行为,也就会把绑定的方法执行,此时标准浏览器会把之前存储的对象(准确来说是堆内存地址)当做实参传递给每一个执行的方法,所以操作一次,即使再多方法中都有event,但是存储的值都是一个(本次操作信息的对象而已)
9.mouseenter&mouseover区别
-
mouseover属性滑过(覆盖)事件,从父元素进入到子元素,属于离开父元素,会触发父元素的mouseout,触发子元素的mouserover;mouseenter属于进入,从父元素进入子元素,并不算离开父元素,不会触发父元素的monseleave,触发子元素的mouseenter
-
moseenter和mouseleave阻止了事件的冒泡传播,而mouseover和mouseout还存在冒泡传播
10.事件委托(事件代理)
利用事件的冒泡传播机制,如果一个容器的后代元素中,很多元素的点击行为(其它事件行为也是)都要做一些处理,此时我们不需要在像以前一样一个个获取一个个的绑定了,我们只需要给容器的click绑定方法即可,这样不管点击的是哪一个后代元素,都会根据冒泡传播的传递机制,把容器的click行为触发,把对应的方法执行,根据事件源,我们可以知道点击的是谁,从而做不同的事件即可
【珠峰笔录】