【ECMAScript】事件

1. 事件流

        JavaScript与HTML交互是通过事件实现的,而事件流是为了页面接收事件的顺序。存在两种事件流方案:事件冒泡流 事件捕获流,IE支持事件冒泡流,Netscape Communicator支持事件捕获流。

1.1 事件冒泡流

        事件冒泡流被定义从最具体的元素(文档树中最深节点)开始触发,然后向上传播至没有那么具体的元素(文档)。示例顺序:div -> body > html -> document -> window

1.2 事件捕获流

        事件捕获流是最不具体的节点最先接收事件,最具体的节点应该最后收到事件(事件捕获是为了在事件抵达最终目标前拦截事件)。示例顺序:window -> document -> html -> body -> div

1.3 DOM事件流

        DOM2 Events规范规定事件流分3个阶段:事件捕获->目标元素接收事件->事件冒泡,事件捕获为拦截事件提供可能。示例顺序:document -> html -> body -> div -> body -> html -> document

规范规定捕获阶段不能命中事件目标,但现代浏览器在捕获阶段在事件目标上触发事件,也即有两个机会处理事件。

2. 事件处理函数

        事件是用户或浏览器执行的动作,如:单击、加载、鼠标悬停,为响应事件调用的函数被称为事件处理程序(或事件监听器),事件处理程序名字以‘on’开头,onclick、onload等。

2.1 HTML事件处理程序(作为HTML的属性)

        将事件处理程序名字作为HTML的属性来指定事件,属性值是JavaScript代码字符串。以这种方式指定事件处理程序,会创建一个函数Fn封装属性的值(即JavaScript代码字符串),Fn有特殊的局部变量event,并且Fn中this指向目标元素。并且Fn中可直接访问document和元素的成员。



Fn的实现类似这样:

function Fn(event) {
    with(document) {
        with(this) {
            // 属性值
        }
     }
}
2.2 DOM0事件处理程序(作为元素(节点)的属性)

        将一个函数赋值给DOM元素的一个事件处理程序属性。此函数内this绑定当前DOM元素。

let btn= document.getElementById('btn');
btn.onclick = function(event) {
    console.log(this.id) // 'btn'
}
// 仅支持绑定一个事件处理程序
// 移除事件处理程序
btn.onclick = null;
2.3 DOM2事件处理程序(使用元素(节点)的addEventListener方法)

        DOM2 events添加了addEventListener和removeListener,此两个方法接收三个参数:事件名、事件处理函数和一个布尔值,true表示捕获阶段调用事件处理程序,false(默认)表示冒泡阶段调用事件处理程序。

let btn = document.getElementById('btn');
btn.addListener('click', () => {
    console.log(this.id);
}, false);
// 事件处理程序同样在被附加到的元素的作用域中运行,即this指向元素本身。
// 且支持多次绑定,会按顺序执行
let btn = document.getElementById('btn');
btn.addListener('click', (event) => {
    console.log('Hello World!');
}, false);
2.4 IE事件处理程序(使用元素(节点)的attachEvent方法)

        IE实现attachEvent和detachEvent方法,此两个方法接收两个参数:事件名和事件处理函数(没有第3个参数,即在冒泡阶段调用事件处理程序,且事件名称需要前缀'on')。

let btn = document.getElementById('btn');
btn.attachEvent('onclick', function() {
    console.log(this === window); // true
});
// this指向window对象
// 也支持绑定多个事件处理程序,按相反顺序执行,后绑定的先执行。
btn.attachEvent('onclick', function() {
    console.log('Hello World!');
});
3. 事件对象

        DOM发生事件时所有相关信息都会被收集并存储在一个名为event的对象中。(注:标灰色的有点出入,不是挂在Event原型对象下的)

Event原型对象的属性和方法

(只读)

说明 示例
Event.prototype.type

功能:获取被触发的事件类型

输出:string

event.type

取值范围:'click' |'mouseover' | 'mouseout' | ...

Event.prototype.target

功能:获取事件目标

输出:Element

event.target

Event.prototype.currentTarget

功能:当前事件处理程序所在的元素

输出:Element

event.currentTarget
Event.prototype.bubbles

功能:表示事件是否冒泡

输出:boolean

event.bubbles

得到true

Event.prototype.cancelable

功能:表示是否可以取消事件的默认行为

输出:boolean

event.cancelable

得到true

Event.prototype.eventPhase 功能:表示调用事件处理程序的阶段,1代表捕获阶段,2代表到达目标,3代表冒泡阶段 event.eventPhase

Event.prototype.detail

功能:事件相关其他信息

输出:number

event.detail
Event.prototype.trusted

功能:true表示事件是由浏览器生成的,false表示开发者通过JS创建的

输出:boolean

event.trusted
Event.prototype.View

功能:与事件相关的抽象视图,等于事件所发生的window对象

输出:AbstractView

event.View
Event.prototype.defaultPrevented

功能:true表示已经调用preventDefault()方法

输出:boolean

event.defaultPrevented
Event.prototype.preventDefault()

功能:取消事件的默认行为,仅cancellable为true才可以调用该方法

输入:无

输出:无

event.preventDefault()
Event.prototype.stopPropagation()

功能:取消所有后续“事件捕获”和“事件冒泡”,仅bubbles为true才可以调用该方法

输入:无

输出:无

event.stopPropagation()

Event.prototype

.stopImmediatePropagation()

功能:取消所有后续“事件捕获”和“事件冒泡”,并阻止调用任何后续事件处理程序

输入:无

输出:无

event

.stopImmediatePropagation()

IE事件对象

Event.prototype.cancelBubble

(读写)

功能:默认false,设置true可以取消冒泡,与stopPropagation()方法相同

event.cancelBubble = true

Event.prototype.returnValue

(读写)

功能:默认ture,设置false可以取消事件默认行为,与preventDefault()方法相同 event.returnValue = false;
Event.prototype.srcElement 功能:事件目标,与target属性相同 event.srcElement
Event.prototype.type 功能:触发的事件类型 event.type
/*
    this和currentTarget都等于document.body,因为它是注册事件处理程序的元素
    target等于按钮本身,它是click事件真正的目标。但它没有事件处理程序,因此冒泡到document.body
*/
document.body.onclick = funtion(event) {
    console.log(event.currentTarget === document.body); // true
    console.log(this === document.body); // true
    console.log(event.target === document.getElementById('btn')); // true
}

// event.type
let btn = document.getElementById('btn');
btn.onclick = function(event) {
    console.log(event.eventPhase); // 2
}

document.body.addEventListener('click', (event) => {
    console.log(event.eventPhase); // 1   
})

document.body.onclick = (event) => {
    cnosole.log(event.eventPhase); // 3
}
4. 事件类型

事件类型

(DOM3 Events)

说明
UIEvent

UIEvent -> Event

用户界面事件,涉及与BOM交互的通用浏览器事件

load:window上当页面加载完成后触发,在frameset上当所有frame都加载完成后触发,img上图片加载完触发,object上当相应对象加载完成后触发(window.onload、)

unload:window上当页面完全卸载后触发,在frameset上当所有frame都卸载完成后触发,object上当相应对象卸载完成后触发

abort:object上在相应对象加载完成前,被用户提前终止下载时触发

error:window上JS报错时触发,在frameset上当一个或多个frame无法完成加载时触发,img无法加载指定图片时触发,object无法加载相应对象时触发

select:文本框select或textarea上用户选择一个或多个字符时触发

resize:window或frame被缩放时触发

scroll:用户滚动包含滚动条的元素时,在元素上触发

归为HTMLEvents

UIEvent.prototype.detail表示在给定位置单击多少次,如果mousedown和mouseup之间移动,detail重置为0

FocusEvent

FocusEvent -> UIEvent

焦点事件,在元素获取和失去焦点时触发

blur:元素失去焦点时触发,不会冒泡

focusout:元素失去焦点时触发,是blur的通用版

focus:元素获得焦点时触发,不会冒泡

focusin:元素获得焦点时触发,是focus的冒泡版

MouseEvent

MouseEvent -> UIEvent -> Event

鼠标事件,使用鼠标在页面执行某些操作时触发 DOM3 Events

click:用户单击鼠标主键(通常是左键)或按键盘回车时触发(同个元素mousedown->mouseup)

dbclick:用户双击鼠标主键(通常是左键)时触发。(两次click)

mouseenter:用户把鼠标光标从元素外部移到元素内部时触发(不冒泡,也不会在光标经过后代元素时触发)
mouseleave:用户把鼠标光标从元素内部移到元素外部时触发(不冒泡,也不会在光标经过后代元素时触发)

mousedown:用户按下任意鼠标键触发(不能通过键盘触发)

mouseup:用户释放鼠标键触发(不能通过键盘触发)

mousemove:鼠标光标在元素上移动时,反复触发(不能通过键盘触发)

mouseover:用户把鼠标光标从元素外部移到元素内部时触发(不能通过键盘触发)——事件的主要目标是获得光标的元素

mouseout:用户把鼠标光标从一个元素移到另一个元素上时触发(移到的元素可以是原始元素的外部元素,也可以是原始元素的子元素,不能通过键盘触发)——事件主要目标是失去光标的元素

示例:比如从div移到body,div上会触发mouseout,关联元素body;body上触发mouseover,关联元素div,事件对象关联属性:event.relatedTarget

mousedown -> mouseup -> click -> mousedown -> mouseup -> click -> dbclick

event.clientX, event.clientY相对浏览器内容窗口左上角的坐标(不考虑页面滚动)

event.pageX, event.pageY相对于页面左上角上坐标

event.screenX, event.screenY相对于屏幕左上角坐标

4个修饰键:shiftKey ctrlKey altKey metaKey

鼠标按键:button 0表示鼠标主键、1表示鼠标中键(通常为滚轮)、2表示鼠标副键

WheelEvent

WheelEvent -> MouseEvent -> UIEvent -> Event

滚轮事件,使用鼠标滚轮(或类似设备)时出发

mousewheel:鼠标滚轮滚动时触发

WheelEvent.prototype.wheelDelta

InputEvent

InputEvent -> UIEvent -> Event

输入事件,向文档中输入文本时出发

textInput:
KeyboardEvent

KeyboardEvent -> UIEvent -> Event

键盘事件,使用键盘在页面上执行某些操作时触发

keydown:用户按下键盘上某个键时触发,持续按住会重复触发

keypress:用户按下键盘上某个键并产生字符时触发,持续按住会重复触发。Esc键也会触发(DOM3 Events推textInput事件)

keyup:用户释放键盘上某个键时触发

4个修饰键:shiftKey ctrlKey altKey metaKey

键码:keyCode

CompositionEvent

CompositionEvent -> UIEvent -> Event

合成事件,在使用某种IME(输入法编辑器)输入字符时触发

compositionstart:在 IME 的文本合成系统打开时触发,表示输入即将开始

compositionupdate:在新字符插入输入字段时触发

compositionend:在 IME 的文本合成系统关闭时触发,表示恢复正常键盘输入

HTML5事件
contextmenu 专门用于表示何时该显示上下文菜单,从而允许开发者取消默认的上下文菜单并提供自定义菜单
beforeunload 用意是给开发者提供阻止页面被卸载的机会
DOMContentLoaded 在 DOM 树构建完成后立即触发,而不用等待图片、JS文件、CSS 文件或其他资源加载完成
readystatechange 旨在提供文档或元素加载状态的信息,但行为有时候并不稳定
pageshow,pagehide 旨在使用浏览器“前进”和“后退”按钮时加快页面之间的切换。
hashchange 用于在 URL 散列值(URL 最后 # 后面的部分)发生变化时通知开发者
设备事件
orientationchange 方便开发者判断用户的设备是处于垂直模式还是水平模式
deviceorientation 如果可以获取设备的加速计信息,而且数据发生了变化,这个事件就会在 window 上触发
devicemotion 这个事件用于提示设备实际上在移动,而不仅仅是改变了朝向
触摸及手势事件
touchstart 手指放到屏幕上时触发(即使有一个手指已经放在了屏幕上)
touchmove 手指在屏幕上滑动时连续触发。在这个事件中调用 preventDefault() 可以阻止滚动
touchend 手指从屏幕上移开时触发
touchcancel 系统停止跟踪触摸时触发。文档中并未明确什么情况下停止跟踪
gesturestart 一个手指已经放在屏幕上,再把另一个手指放到屏幕上时触发
gesturechange 任何一个手指在屏幕上的位置发生变化时触发
gestureend 其中一个手指离开屏幕时触发

还有其他很多类事件,可以参考一些专业文档。

5. 内存与性能

        页面中事件处理程序的数量和页面整体性能直接相关,一是函数都是对象,占用内存空间,对象越多,性能越差;二是指定事件处理程序所需访问DOM次数会先期造成整个页面交互的延迟。

5.1 事件委托

        比如可以在整个指定一个onclick事件处理程序,而不给每个元素指定事件处理程序。适合事件委托的事件包括:click、mousedown、mouseup、keydown和keypress,不适合事件委托:mouseover和mouseout,不好处理。



    
        事件委托
    
    
        
        
    
5.2 删除事件处理程序

        把事件处理程序指定给元素后,在浏览器代码和负责页面交互的 JavaScript 代码之间就建立了联系,联系建立越多,页面性能越差,因为需要及时删除不用的事件处理程序。



    
        事件委托
    
    
         
6. DOM事件模拟

        事件doucment.createEvent方法创建一个event对象。

let btn = document.getElementById("myBtn");
// 创建 event 对象
let event = document.createEvent("MouseEvents");
// 初始化 event 对象
event.initMouseEvent("click", true, true, document.defaultView,
0, 0, 0, 0, 0, false, false, false, false, 0, null);
// 触发事件
btn.dispatchEvent(event);

注:以上,如有不合理之处,还请帮忙指出,大家一起交流学习~

你可能感兴趣的:(ecmascript,前端,开发语言)