携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第N天,点击查看活动详情 >>
EventTarget
EventTarget 不仅仅 只有 HTMLElement ,其他的需要通讯的,比如 XHR 也是 EventTarget
addEventListener
target.addEventListener(type, listener[, useCapture])
target.removeEventListener(type,listener[, options]);
Listener:
-
函数:
- 添加了多个 callback,则按添加的顺序调用
- 添加了多个同一个 callback,则只调用一次
-
实现了 handleEvent 的对象
useCapture:是一个布尔值代表是否在捕获阶段触发,还可以是一个options 对象
capture:布尔值,如果设为true,表示监听函数在捕获阶段触发,默认为false,在冒泡阶段触发。
once:布尔值,如果设为true,表示监听函数执行一次就会自动移除,后面将不再监听该事件。该属性默认值为false。passive:布尔值,设为true时,表示禁止监听函数调用preventDefault()方法。如果调用了,浏览器将忽略这个要求,并在控制台输出一条警告。该属性默认值为false。signal:该属性的值为一个 AbortSignal 对象,为监听器设置了一个信号通道,用来在需要时发出信号,移除监听函数。
removeEventListener
target.removeEventListener(type,listener[, options]);
target.removeEventListener(type,listener[,useCapture]);
useCapture
指定需要移除的 [EventListener](<https://developer.mozilla.org/zh-CN/docs/conflicting/Web/API/EventTarget/addEventListener_380cb5f366307beb2c072f74e561ee98>) 函数是否为捕获监听器。如果无此参数,默认值为 false。
如果同一个监听事件分别为“事件捕获”和“事件冒泡”注册了一次,这两次事件需要分别移除。两者不会互相干扰。
target.addEventListener("click", listener, true);
target.removeEventListener("click", listener, false); // 不会生效哦
options
合法的属性只有 capture 其实和直接使用 useCapture 无异
dispatchEvent
target.dispatchEvent(event)
这里的 dispatch(派发) 的目标就是 target,相当于手动去触发一些方法;
该方法返回一个布尔值,只要有一个监听函数调用了Event.preventDefault(),则返回值为false,否则为true。
para.addEventListener('click', hello, false);
var event = new Event('click');
para.dispatchEvent(event);
事件调用的三种方法
HTML: on - xx
<body onload="doSomething()">
<div onclick="console.log('触发事件')">
原生的Value是 JS片段(要执行的代码),而React 的 OnXX 的 Value 是一个 函数对象
使用这个方法指定的监听代码,只会在 冒泡阶段 触发。
HTMLElement 的 JS 属性
div.onclick = function(){}
使用这个方法指定的监听函数,也是只会在 冒泡阶段 触发。
addEventListener
不再赘述
This 指向问题
普通函数:执行触发的元素
箭头函数:外部作用域的 thi
事件的传播模型
三个阶段划分
- capture phase : 从
window对象传导到目标节点(上层传到底层),称为“捕获阶段”。 - target phase:在目标节点上触发,称为“目标阶段”。
- bubbling phase:从目标节点传导回
window对象(从底层传回上层),称为“冒泡阶段”。
比如
上使用 addEventListener 添加了 两个阶段的 click 事件;
但是实际上真正点击的时候 是在 target phase 阶段触发了两个事件
<p id="pp">PP</p>
let p = document.getElementById('pp')
p.addEventListener('click',()=>{
console.log("CLICK BuBBle")
}, false)
p.addEventListener('click',()=>{
console.log("CLICK Capture")
}, true)
/*
先打印 Capture, 再打印 Bubble
*/
事件委托
<div id="fa">
<p id="pp">PP</p>
</div>
let fa = document.getElementById('fa')
fa.addEventListener('click',(e)=>{
e.stopImmediatePropagation();
console.log(e);
})
stopPropagation:当前元素的回调还是会被触发
stopImmediatePropagation:接下来的元素的回调会被砍掉,但是目前执行的回调还会继续执行
Event 对象
构造函数
event = new Event(type, options);
type: 事件名称
options:
- Bubbles: false
- Concelable: false -> 表示事件是否可以被取消,即能否用
Event.preventDefault()取消这个事件。
preventDefault
告诉 user agent :如果此事件没有被显式处理,它默认的动作也不应该照常执行。此事件还是继续传播,除非碰到事件侦听器调用[stopPropagation()](<https://developer.mozilla.org/zh-CN/docs/Web/API/Event/stopPropagation>) 或[stopImmediatePropagation()](<https://developer.mozilla.org/zh-CN/docs/Web/API/Event/stopImmediatePropagation>),才停止传播。
React 自定义事件
面试题:
为什么要提出浏览器的事件模型?在当前的事件模型中,哪些事件可以冒泡,哪些不会冒泡,为什么?不冒泡的元素,如何来实现事件代理?
- 在GUI程序中,可以触发某个特定的元素的某个事件,比如点击一个嵌套的同心div,那么到底哪一个div会拥有这个点击事件?实际上难以确定点击者的意图,团队给出的解决方式是所有div都将拥有这个事件,于是产生了事件流模型。
- 不能冒泡的事件,如error、blur、load等;
- 能知道通过event.bubbles来判断事件是否支持冒泡,也能说出自定义事件通过设置该属性修改是否支持冒泡,其次也要知道对于不能冒泡的事件可以尝试用捕获的方式,如在addEventListener的第三个参数设置为true。
事件代理有哪些优点?
把事件委托到其父对象上,借助事件冒泡机制,实现对节点的事件代理。
优点
- 可以大量节省内存占用,减少事件注册
- 当新增子对象时无需再次对其绑定事件,对于动态内容部分尤为合适
React 事件的实现机制?与原生 DOM 事件有什么区别?
react 17中事件就不再注册在document上,而是你的组件所绑定的container上- React 绑定的是 冒泡阶段,所以如果在React中混入了一些原生的事件,在捕获阶段或者捕获阶段就阻止他传播的话,React的回调就不执行了
- React 通过对象池的形式管理合成事件对象的创建和销毁,减少了垃圾的生成和新对象内存的分配,提高了性能