【ECMAScript】事件

2023-12-26 09:53:33
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和元素的成员。

<input onclick="console.log(event.type)"/>
<input onclick="console.log(this.value)"/>
<input onclick="console.log(value)"/>

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、<body loload="console.log('Loaded')"/>)

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,不好处理。

<!DOCTYPE html>
<html>
    <head>
        <title>事件委托</title>
    </head>
    <body>
        <ul id='myLinks'>
            <li id='goSomeWhere'>Go somewhere</li>
            <li id='doSomething'>Do something</li>
            <li id='sayHi'>Say hi</li>
        </ul>
        <script>
            let list = document.getElementById('myLinks');
            list.addEventListener('click', (event) => {
                let target = event.target;
                switch(target.id) {
                    case "doSomething":
                        document.title = "I changed the document's title";
                        break;
                    case "goSomewhere":
                        location.href = "http:// www.wrox.com";
                        break;
                    case "sayHi":
                        console.log("hi");
                        break;
                }
            })
        </script>
    </body>
</html>
5.2 删除事件处理程序

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

<!DOCTYPE html>
<html>
    <head>
        <title>事件委托</title>
    </head>
    <body>
         <div id="myDiv">
            <input type="button" value="Click Me" id="myBtn">
         </div>
        <script>
            let btn = document.getElementById("myBtn");
            btn.onclick = function() {
                // 执行操作
                btn.onclick = null; //  删除事件处理程序
                document.getElementById("myDiv").innerHTML = "Processing...";
            };
        </script>
    </body>
</html>
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);

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

文章来源:https://blog.csdn.net/weixin_45620943/article/details/135173417
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。