Javascript学习笔记-Event事件

Javascript Event事件.png

在前端开发过程中,页面交互过程和事件机制密不可分,一直以来对于事件相关机制了解的不够深刻,没有好好进行了解,最近花了一点时间,梳理了一下事件机制以及相关常用的事件。

1. EventTarget

1.1 EventTarget对象

事件对象是事件的基础,事件都不是独立存在的,需要绑定在一个事件对象上,监听对象的变化,当对象发生相关事件变化时触发对应回调。

window, document, Element都是EventTarget对象,一些非节点元素也是EventTarget,比如Ajax中的XMLHttpRequest对象

1.2 EventTarget对象方法

1.2.1 addEventListener

利用addEventListener可以给EventTarget增加Event事件,方法接受最多三个参数:

addEventListener(type, listener[, options/capture])

type: 事件类型,可以是浏览器支持的DomEvent,也可以是自己自定义的CustomEvent

listener: EventListenerUserAgent将事件发送给EventListener的时候,会触发listener对象中的handleEvent方法。由于历史遗留,通常我们写EventListener的时候第二个参数都是一个方法

eventTarget.addEventListener('click', ev => {})

实际上等价于

eventTarget.addEventListener('click', {handleEvent: ev => {}})

options/caputure: 第三个参数为可选,接受一个Object/Boolean,接受Object可以指定三个属性:capture, once, passive

capture: 设置事件捕获方式,默认为false,不使用捕获,事件使用冒泡机制;设置为true,使用捕获机制
once: 事件是否只触发一次
passive: EventListener内部是否可以使用event.preventDefault(),设置为true的时候将不能使用,否则会提示错误信息:
Unable to preventDefault inside passive event listener invocation.

简明一下浏览两种事件触发机制:冒泡和捕获,冒泡是从内向外,捕获是从外向内,借用网上经典的一个图示来说明:

image.png

PS:

  1. 老版本的IE浏览器使用attachEvent来作为addEventListener的替代方法
  2. 同一个事件多次绑定相同的函数并不会多次触发
    例如:
document.addEventListener('click', () => {console.log('click')})
document.addEventListener('click', () => {console.log('click')})

这样进行绑定,当点击页面的时候会触发两次,但是如果按照以下方式进行绑定,则只会触发一次

function click() {
  console.log('click')
}
document.addEventListener('click', click)
document.addEventListener('click', click)

1.2.2 removeEventListener

移除绑定的EventListener对象

removeEventListener(type, listener[, useCapture])

同样支持三个参数,第一个参数type为移除的事件类型,第二个参数为EventListener对象,必须和addEventListener添加的对象是同一个对象/方法,第三个参数为移除冒泡还是移除捕获的事件

1.2.3 dispathEventListener

通常我们通过增加部分已经被定义的EventListener事件类型,例如:click, input等,直到用户发生交互行为或EventTarget对象操作结束,触发绑定的事件;除此以外,其实可以自定义EventTarget以及CustomEvent,并且利用dispatchEvent在任意时候手动触发相关事件,例如:

let eventTarget = new EventTarget();
let event = new CustomEvent('myEvent', {detail: 'test' });
eventTarget.addEventListener('myEvent', () => {
    console.log('trigger event')
})
eventTarget.dispatchEvent(event);

2. Events

2.1 Event

Event是所有Event对象的基类,包含了一些基础的属性

2.1.1 只读属性

bubbles: 判断事件是否冒泡

cancelable: 判断事件是否可以取消

composed: 判断事件是否可以从ShadowDom传递到ShadowDom

currentTarget: 事件注册的对象

defaultPrevented: 判断事件是否执行了preventDefault()

eventPhase: 获得事件触发阶段(0: Event.NONE, 1: Event.CAPTURE_PHASE捕获阶段, 2: Event.AT_TARGET到达触发目标阶段, 3: Event.BUBBLING_PHASE冒泡阶段)

target:事件发送的原始目标,和currentTarget区别在于,currentTarget是事件注册的目标(有可能是target的父节点)

type: 触发事件类型

timeStamp: 事件从创建成功后到触发时所用的时间,单位毫秒

isTrusted: 判断事件是用户触发还是非用户触发,true代表用户触发的事件

2.1.2 读写属性

cancelBubble: Event.stopPropagation()历史别名,设置为true以后会阻止事件冒泡

returnValue: 已经被preventDefault()替代,设置为false以后会阻止默认的事件

srcElement: IE旧版本浏览器中的target对象

2.1.3 方法

composedPath(): 获取触发事件路径,会返回从targetWindow的事件路径数组

preventDefault(): 阻止默认的事件,例如input的默认事件是输入,如果keyup/keydown事件使用了preventDefault(),则输入框将无法输入字符

stopImmediatePropagation(): 阻止其他type相同的事件的触发,也就是同一个EventTarget的相同type事件只会触发一个

stopPropagation():阻止事件的冒泡/捕获

2.2 事件列举(不完全列举)

大部分的type事件有特定事件类型,不同的浏览器对具体事件类型支持的程度不一而同,列举一些常用的事件子类,及会得到该子类的type类型

2.2.1 FocusEvent

blur: 失去焦点,不会冒泡

focusout: 失去焦点,支持冒泡

focus: 获得焦点,不会冒泡

focusin: 获得焦点,支持冒泡

2.2.2 MouseEvent

mouseenter: 鼠标移入元素

mouseleave: 鼠标移出元素

mouseover: 鼠标移入元素/子元素(给父元素绑定以后,从父元素到子元素,或者从子元素到父元素都会触发)

mouseout: 鼠标移出元素/子元素

mousemove: 鼠标在元素上持续移动

mousedown: 鼠标在元素上点击

mouseup: 鼠标在元素上释放点击

click: 鼠标点击(按下和释放必须同时触发),支持冒泡

dbclick: 鼠标双击

contextmenu: 鼠标右键打开菜单栏(监听该事件后可以使用event.preventDefault()阻止打开右键菜单)

wheel: 鼠标滚轮的滚动

2.2.3 CompositionEvent

有只读的data属性,event.data可以获取到正在输入到字符串

compositionend: 段落文本组成完成,比如:输入法组件关闭

compositionstart: 文字输入前触发,不同于keydown,在输入法控件打开时候触发(据说也支持语音识别打开)

compositionupdate: 输入法打开后,文字输入过程触发

2.2.4 ErrorEvent

error: 资源加载失败,页面throw Error()可以进行捕获

2.2.5 InputEvent

input: 对于<input type="text">, <textarea>, <select>元素值发生更改时同步触发,对于<input type="radio">, <input type="checkbox">的元素,每次切换控件时触发,contenteditable=true内的内容变更也会触发

change: 不同于input,不一定每一次变化都会触发,焦点遗失/会车等操作会触发

2.2.6 KeyboardEvent

keydown: 键盘按键按下,无论是否产生字符都会触发

keypress: 键盘按键按下,产生字符时触发,因此ctrl,shift不产生字符都键位不会触发

keyup: 键盘按键释放

2.2.7 AnimationEvent

animationstart: CSS动画开始

animationedn: CSS动画结束

animationiteration: CSS动画重复开始时触发

2.2.8 TransitionEvent

*transtionstart: CSS中transition实际发生时,会在transition-delay后触发,实验性质事件

transitionend: CSS的transition结束的时候触发

*transitionrun: transition-delay前触发,实验性质事件

2.2.9 ClipboardEvent

cut: 发生剪切时触发,包括键盘快捷键和菜单栏中的操作

copy: 发生复制时触发,包括键盘快捷键和菜单栏操作和document.execCommand('copy'),可以通过event.preventDefault()阻止复制,可以通过event.clipboardData.setData()getData()来获取内容

paste: 发生粘贴时触发

2.2.10 TouchEvent

主要是使用在触屏上的监听

touchcancel: 一个或者多个触点触碰时,草畜了触点支持的数量而被取消时触发

touchend: 一个或多个触点触碰结束时触发

touchemove: 一个或多个触点移动的时候触发

touchstart: 一个或多个触点开始触碰时触发

2.2.11 PointerEvent

由于屏幕设备的扩展,所以操作手段不在局限于鼠标,所以提供了一套和鼠标操作相同的API,来支持类似的触控事件

pointerover: 和mouseover等同

pointerenter: 和mouseenter等同

pointerdown: 和mousedown等同

pointermove: 和mousemove等同

pointerup: 和mouseup等同

pointerout: 和mouseout等同

pointerleave: 和mouseleave等同

2.2.12 DragEvent

拖动相关事件,其实分为了拖动元素事件和释放区域事件两类

拖动元素事件:

dragstart: 元素开始拖动

drag: 元素拖动中(每350ms触发一次)

dragend: 元素拖动结束

释放区域事件

dragenter: 拖动进入了drop目标区域,进入子节点也会反复触发

dragover: 元素在drop目标区域中移动(每350ms触发一次),需要设置event.preventDefault()元素才能在该区域drop

dragleave: 拖动离开了drop目标区域,进入子节点也会触发

drop: 元素在drop目标区域中拖动被释放

2.2.13 MediaEvent

媒体播放相关事件,针对H5视频<video>和音频<audio>播放器的事件

durationchange: duration属性更新

loadedmetadata: metadata属性加载

loadeddata: media完成加载

canplay: 可以播放media的时候触发(拖动进度条会触发)

canplaythrough: 可以播放整个media时触发(拖动进度条会触发)

ended: media播放结束触发

stalled: 请求media数据,但是剧没有如预期到来时触发

suspend: media请求挂起时触发

play: media播放开始

playing: media播放中

pause: media暂停

waiting: 缺少数据加载

seeking: 时间进度条操作变动

seeked: 时间进度条操作变动停止

ratechannge: 播放速率改变

timeupdate: currentTime属性更新(播放过程中时间变动)

volumechange: 音量调节

2.2.14 其他

select: 文本选中,只能监听inputtextarea的选中(该事件和document.execCommand('copy')可以实现点击复制功能)

DOMContentLoaded: DOM加载完成,不会等待样式,图片渲染,Chrome中的devtool中Network中可以看到相关加载时间应该就是使用该监听来处理的

beforeunload: 离开页面前触发,设置event.returnValue=true,将弹出提示消息来确认是否关闭

offline/online: 在浏览器丢失网络/获得网络时触发

beforeprint: 准备打印/打开打印预览时触发

afterprint: 开始打印/关闭打印预览后时触发

reset/submit: 表单重置/提交按钮点击时触发

fullscreenchange/resize/scroll:浏览器全屏/尺寸修改/滚动时触发

hashChange: URL中#以及#后面的值发生变化的时候触发,可能前端框架的路由机制可以用该监听实现

readstatechange: documentreadyState发生变化的时候触发,可以作为DomContentLoaded的替代

invalid: h5表单提交,绑定元素不符合规则的时候触发(input元素可以设置验证规则属性,例如:required, max, min, pattern,可以通过伪类:invalid获取到数据)

message: WebWorks信息接受时触发

2.3 CustomEvent

1.2.3 dispathEventListener 中提到了CustomEvent,可以根据自己的需求定义事件,并通过dispatchEvent来触发绑定的自定义事件

3. 参考

MDN Event reference

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349