1. 事件 Event
事件的本质是: 程序各个组成部分之间的一种通信方式,也是 异步编程 的一种实现
DOM 的事件操作 分为: 监听 和 触发 都定义在 EventTarget 接口____
所有节点对象都部署了 EventTarget 接口,其他一些需要事件通信的浏览器内置对象(比如,XMLHttpRequest、AudioNode、AudioContext)也部署了这个接口。
.addEventListener(); 绑定事件的监听函数
.removeEventListener(); 移除事件的监听函数
.dispatchEvent(); 触发事件
- EventTarget.addEventListener(eventType, listener[, useCapture]);
用于在当前节点或对象上,定义一个特定事件的监听函数。
一旦这个事件发生,就会执行监听函数。
可以为针对当前对象的同一个事件,添加多个不同的监听函数。这些函数按照添加顺序触发,即先添加先触发。
如果为同一个事件多次添加同一个监听函数,该函数只会执行一次,多余的添加将自动被去除(不必使用removeEventListener方法手动去除)。
- 该方法没有返回值
- 参数:
eventType 事件名称,大小写敏感。
listener 监听函数。事件发生时,会调用该监听函数。
- 注意:
- 除了监听函数,还可以是一个 具有 handleEvent 方法的对象
-
btn.addEventListener(‘click‘, { handleEvent: function (event) { console.log(‘click‘); } }, false);
[useCapture] 是否在捕获阶段(capture)触发(参见后文《事件的传播》部分),默认为 false(监听函数只在冒泡阶段被触发)。该参数可选
- 注意:
- 除了布尔值
useCapture
,还可以是一个属性配置对象 - 该对象有以下属性:
capture: 布尔值,表示该事件是否在捕获阶段触发监听函数。
once: 布尔值,表示监听函数是否只触发一次,然后就自动移除。
passive: 布尔值,表示监听函数不会调用事件的 preventDefault 方法。默认为 true 如果监听函数调用了,浏览器将忽略这个要求,并在监控台输出一行错误。
- 希望事件监听函数只执行一次,可以打开属性配置对象的once属性
-
ele.addEventListener(‘click‘, function (event) { // 只执行一次的代码 }, {once: true});
- 如果希望向监听函数传递参数,可以用匿名函数包装一下监听函数
-
var box = document.getElementById(‘div1‘); box.addEventListener(‘click‘, function () { myPrint(‘Hello‘); }, false); function myPrint(x) { console.log(x); }
- EventTarget.removeEventListener(eventType, listener);
用来移除 .addEventListener() 方法添加的事件监听函数。
该方法没有返回值
listener 在绑定时是 匿名函数,那么将无法直接用 .removeEventListener() 移除。
- EventTarget.dispatchEvent(Event对象的实例)
在当前节点上触发指定事件,从而触发监听函数的执行。
- 返回一个布尔值
只要有一个监听函数调用了 Event.preventDefault(),则返回值为 false,否则为 true
-
ele.addEventListener(‘click‘, hello, false); var event = new Event(‘click‘); ele.dispatchEvent(event); // 主动触发 click 事件
2. 浏览器的事件模型
就是通过监听函数(listener)对事件做出反应。
事件发生后,浏览器监听到了这个事件,就会执行对应的监听函数。
____这是事件驱动编程模式(event-driven)的主要编程方式
- 绑定事件监听函数的三种方法:
在 html 标签 中直接绑定
- 只会在冒泡阶段触发
- 缺点: 违反了 HTML 与 JavaScript 代码相分离的原则
-
<body onload="doSomething()"> <!-- 等同于 document.body.setAttribute("onload", "doSomething()"); --> <div id="box" onclick="console.log(‘触发事件‘)"> // this 输出 box
在 js 代码中,给元素对象 的事件属性绑定监听函数
- 众所周知的 DOM0 级事件模型 绑定方式,也只会在冒泡阶段触发
- 缺点: 同一个事件只能定义一个监听函数,也就是说,如果定义两次onclick属性,后一次定义会覆盖前一次
-
window.onload = doSomething; div.onclick = function (event) { console.log(‘触发事件‘); };
使用 EventTarget.addEventListener() 绑定
- 众所周知的 DOM2 级事件模型 绑定方式
-
window.addEventListener(‘DOMContentLoaded‘, doSomething, false);
- 优点:
除了 DOM 节点,其他对象(比如window、XMLHttpRequest等)也有这个接口,等于是整个 JavaScript 统一的监听函数接口
能够指定在哪个阶段(捕获阶段还是冒泡阶段)触发监听函数
同一个事件可以添加多个监听函数
3. 事件的传播
使得同一个事件会在多个节点上触发
- 分成三个阶段
“捕获阶段”(capture phase) 从 window 对象 传导到 目标节点
“目标阶段”(target phase) 在目标节点上触发
“冒泡阶段”(bubbling phase) 从 目标节点 传导回 window对象
-
var phases = { 1: ‘capture‘, 2: ‘target‘, 3: ‘bubble‘ }; var div = document.querySelector(‘div‘); var p = document.querySelector(‘p‘); div.addEventListener(‘click‘, callback, true); div.addEventListener(‘click‘, callback, false); p.addEventListener(‘click‘, callback, true); p.addEventListener(‘click‘, callback, false); function callback(event) { console.log("Tag: " + event.currentTarget.tagName, "EventPhase: " + phases[event.eventPhase]); }; // 点击以后的结果 // Tag: ‘DIV‘. // EventPhase: ‘capture‘ // Tag: ‘P‘ // EventPhase: ‘target‘ // Tag: ‘P‘ // EventPhase: ‘target‘ // Tag: ‘DIV‘ //EventPhase: ‘bubble‘
- 注意:
浏览器总是假定 click 事件的目标节点,就是点击位置嵌套最深的那个节点
事件传播的最上层对象是window,接着依次是document,html(document.documentElement)和body(document.body)
也就是说,上例的事件传播顺序,
在捕获阶段依次为window、document、html、body、div、p
在冒泡阶段依次为p、div、body、html、document、window。
- 事件委派 / 事件代理(delegation)
把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件
- 优点:
只要定义一个监听函数,就能处理多个子节点的事件,而不用在每个<li>节点上定义监听函数
而且以后再添加子节点,监听函数依然有效
- 如果希望事件到某个节点为止,不再传播,可以使用事件对象的 event.
stopPropagation()
方法
但是,stopPropagation方法只会阻止事件的传播,
不会阻止该事件触发 <p> 节点的其他 click 事件的监听函数。
也就是说,不是彻底取消click事件
-
p.addEventListener(‘click‘, function (event) { event.stopPropagation(); console.log(1); // 不会触发 }); p.addEventListener(‘click‘, function(event) { // 会触发 console.log(2); });
- 如果想要彻底取消该事件,不再触发后面所有click的监听函数,可以使用 event.stopImmediatePropagation() 方法
4. Event 对象
Event 对象本身就是一个构造函数,可以用来生成新的实例
-
event = new Event(type, options);
接收两个参数:
- type 字符串,表示 事件的名称
- options 对象,表示 事件对象的配置。
该对象主要有下面两个属性
- bubbles 布尔值,可选,默认为 false,表示事件对象是否冒泡
如果不是显式指定 bubbles 属性为 true,生成的事件就只能在 “捕获阶段” 触发监听函数
- cancelable 布尔值,可选,默认为false,表示事件是否可以被取消,
即能否用 event.preventDefault() 取消这个事件。
一旦事件被取消,就好像从来没有发生过,不会触发浏览器对该事件的默认行为
- 实例属性
Event.bubbles
表示当前事件是否会冒泡。
返回一个布尔值,除非显式声明,Event
构造函数生成的事件,默认是不冒泡的。
该属性为只读属性,用来判断 Event 实例是否可以冒泡
Event.eventPhase
表示事件目前所处的阶段。
返回一个整数常量,该属性只读
- 0,事件目前没有发生。
1,事件目前处于捕获阶段,即处于从祖先节点向目标节点的传播过程中。
2,事件到达目标节点,即 Event.target 属性指向的那个节点。
3,事件处于冒泡阶段,即处于从目标节点向祖先节点的反向传播过程中。
Event.cancelable
表示事件是否可以取消。
返回一个布尔值,该属性为只读属性,
一般用来判断 Event 实例是否可以被取消
- 当 Event.cancelable 属性为true 时,调用 Event.preventDefault(); 就可以取消这个事件,阻止浏览器对该事件的默认行为。
- 如果事件不能取消,调用 Event.preventDefault() 会没有任何效果。
- 所以使用这个方法之前,最好用 Event.cancelable 属性 判断一下是否可以取消
-
/**** 封装 禁止浏览器默认行为 ****/function preventEvent(event) { if (event.cancelable) { event.preventDefault(); } else { console.warn(‘This event couldn\‘t be canceled.‘); console.dir(event); } }
Event.cancelBubble
阻止事件的传播。 如果设为true,相当于执行Event.stopPropagation()
是一个布尔值
Event.defaultPrevented
表示该事件是否调用过 Event.preventDefault() 方法。
返回一个布尔值,该属性只读。
Event.currentTarget
返回 事件当前所在的节点,即正在执行的监听函数所绑定的那个节点,随事件传播过程而变化
Event.target
返回 原始触发事件的那个节点,即事件最初发生的节点,事件传播过程中是固定不变的
Event.type
表示事件类型。
返回一个字符串,事件的类型是在生成事件的时候。
该属性只读
Event.timeStamp
返回一个毫秒时间戳,表示事件发生的时间。
它是相对于网页加载成功开始计算的。
- 实例计算鼠标移动速度,每秒移动的 px 值
-
var previousX; var previousY; var previousT; window.addEventListener(‘mousemove‘, function(event) { if (previousX !== undefined && previousY !== undefined && previousT !== undefined ){ var deltaX = event.screenX - previousX; // 获取 当前的 xOffset var deltaY = event.screenY - previousY; // 获取 当前的 yOffset var deltaD = Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2)); var deltaT = event.timeStamp - previousT; console.log(deltaD / deltaT * 1000); // 速度 = 路程 / 时间 }; previousX = event.screenX; // 获取移动前的 x previousY = event.screenY; // 获取移动前的 y previousT = event.timeStamp; // 获取当前时间戳 });
Event.isTrusted
表示该事件是否由真实的用户行为产生。
返回一个布尔值
比如,用户点击链接会产生一个 click 事件,该事件是用户产生的;Event 构造函数生成的事件,则是脚本产生的。
Event.detail
该属性返回一个数值,表示事件的某种信息。
只有浏览器的 UI (用户界面)事件才具有此属性。
具体含义与事件类型相关。
比如,
对于 click 和 dbclick 事件,Event.detail 是鼠标按下的次数(1表示单击,2表示双击,3表示三击);
对于鼠标滚轮事件,Event.detail 是滚轮正向滚动的距离,负值就是负向滚动的距离,返回值总是 3 的倍数。
- 实例方法
Event.preventDefault()
取消浏览器对当前事件的默认行为。
比如点击链接后,浏览器默认会跳转到另一个页面,使用这个方法以后,就不会跳转了;
再比如,按一下空格键,页面向下滚动一段距离,使用这个方法以后也不会滚动了。
再比如,浏览器的默认行为是单击会选中单选框,取消这个行为,就导致无法选中单选框
该方法生效的前提是,事件对象的 cancelable 属性为true,如果为 false,调用该方法没有任何效果
注意,该方法只是取消事件对当前元素的默认影响,不会阻止事件的传播。
如果要阻止传播,可以使用 event.stopPropagation() 或 event.stopImmediatePropagation() 方法
- 实例: 为文本输入框设置校验条件。如果用户的输入不符合条件,就无法将字符输入文本框。
-
// HTML 代码为 // <input type="text" id="my-input" /> var input = document.getElementById(‘my-input‘); input.addEventListener(‘keypress‘, checkName, false); function checkName(e) { if (e.charCode < 97 || e.charCode > 122) { e.preventDefault(); } }
上面代码为文本框的
keypress
事件设定监听函数后,将只能输入小写字母,否则输入事件的默认行为(写入文本框)将被取消,导致不能向文本框输入内容
Event.stopPropagation()
阻止事件在 DOM 中继续传播,防止再触发定义在别的节点上的监听函数,
但是不包括在当前节点上其他的事件监听函数
Event.stopImmediatePropagation()
阻止同一个事件的所有监听函数被调用,不管监听函数定义在当前节点还是其他节点。
也就是说,该方法阻止事件的传播,比Event.stopPropagation()更彻底
Event.composedPath()
返回一个节点数组,成员是事件的最底层节点和依次冒泡经过的所有上层节点
原文地址:https://www.cnblogs.com/tianxiaxuange/p/10099101.html