原生DOM事件、react16、17和Vue合成事件
目录
原生DOM事件
注册/绑定事件
DOM事件级别
DOM0:onclick传统注册:
唯一(同元素的(不)同事件会覆盖)
没有捕获和冒泡的,只有简单的事件绑定
DOM2:addEventListener监听注册:可添加多个,优先级低于传统注册,IE9以上
引入了事件捕获、冒泡阶段
元素.addEventListener(事件类型type,执行函数handler[,ueseCapture捕获true/false]) 默认值为false(即 使用事件冒泡)
DOM3:对 DOM 2 级事件的扩展。
引入事件类型,如 input、change 等
加入特性
异步执行:
自定义事件:CustomEvent构造函数 创建, dispatchEvent 方法触发
事件的停止:stopPropagation(),preventDefault()
DOM事件流:捕获->冒泡(默认)
执行顺序
具体的元素>层级高document(包括react16事件委托)
同层级的按注册顺序
不支持冒泡:与用户界面交互或设备输入相关
焦点、鼠标进出、加载/卸载、尺寸、表单改变(/提交/重置)
阻止事件
DOM树上的传播(捕获/冒泡):event.stopPropagation()
阻止剩下同事件+event.stopPropagation():event.stopImmediatePropagation()
默认行为(链接的跳转、表单的提交):event.preventDefault():
事件处理位置/DOM元素上的handler值
原生事件:事件处理函数
React:nonp空函数
事件被分解后绑定在document
React17事件统一绑定container
事件保存在fiberNode对象的memoizedProps 和 pendingProps属性中
(React17取消)事件池:创建/回收->数组弹出
1.事件注册(浏览器):初始化事件参数
1.事件合成:用插件机制 初始化事件参数+映射原生事件类型
2.事件绑定:注册监听器,绑定 dispatchEvent统一事件处理
3.事件触发:批量更新处理
Vue
与react区别:不暴露给开发者
绑定处理:模板和指令(@)
用法
原生DOM事件
注册/绑定事件
DOM事件级别
DOM0:onclick传统注册:
唯一(同元素的(不)同事件会覆盖)
没有捕获和冒泡的,只有简单的事件绑定
// 第一种
<button onclick="console.log(1)">点击</button>
// 第二种
<button id="btn">点击</button>
const btn = document.querySelector('#btn')
btn.onclick = function () {}
DOM2:addEventListener监听注册:可添加多个,优先级低于传统注册,IE9以上
引入了事件捕获、冒泡阶段
元素.addEventListener(事件类型type,执行函数handler
[,ueseCapture捕获true/false]) 默认值为false(即 使用事件冒泡)
<button id="btn">点击</button>
const btn = document.querySelector('#btn')
btn.addEventListener('click', () => {})
DOM3:对 DOM 2 级事件的扩展。
引入事件类型,如 input
、change
等
加入特性
异步执行:
element.addEventListener('click', function(event) {
setTimeout(function() {
// 异步执行的代码
console.log('异步执行的代码');
}, 0);
});
自定义事件:CustomEvent构造函数
创建, dispatchEvent
方法触发
// 创建自定义事件
var customEvent = new CustomEvent('myEvent', { detail: { key: 'value' } });
// 添加事件监听器
element.addEventListener('myEvent', function(event) {
console.log('自定义事件触发了', event.detail.key);
});
// 触发自定义事件
element.dispatchEvent(customEvent);
事件的停止:stopPropagation(),preventDefault()
DOM事件流:捕获->冒泡(默认)
- 事件捕获:由外往内,从事件发生的根节点开始,逐级往下查找,一直到目标元素。
- 事件冒泡:由内往外,从具体的目标元素触发,逐级向上传递,直到根节点。
element.addEventListener(event, function[, useCapture]);
//useCapture 默认为false,即冒泡阶段调用事件处理函数,
//为ture时,在事件捕获阶段调用处理函数
事件队列:捕获事件,将 unShift
到执行队列的前面,冒泡事件,将 push
到执行队列后面
执行顺序
具体的元素>层级高document(包括react16事件委托)
同层级的按注册顺序
不支持冒泡:与用户界面交互或设备输入相关
焦点、鼠标进出、加载/卸载、尺寸、表单改变(/提交/重置)
-
focus
和blur
事件:这些事件与元素获得或失去焦点相关,通常不会冒泡到父元素。 -
mouseenter
和mouseleave
事件:这些事件在鼠标指针进入或离开元素时触发,不会冒泡。 -
load
事件:当页面或资源加载完成时触发,不会冒泡到父元素。 -
unload
事件:在页面即将卸载时触发,不会冒泡。 -
resize
事件:当浏览器窗口大小改变时触发,不会冒泡。 -
submit
事件:当表单提交时触发,通常不会冒泡到父元素。 -
reset
事件:当表单重置时触发,不会冒泡。 -
change
事件:当用户改变表单元素的值时触发,通常在元素自身上触发而不会冒泡。
阻止事件
DOM树上的传播(捕获/冒泡):event.stopPropagation()
<div id="parent">
<button id="myButton">Click me</button>
</div>
<script>
const parent = document.getElementById('parent');
const button = document.getElementById('myButton');
parent.addEventListener('click', function(event) {
console.log('Parent handler');
});
button.addEventListener('click', function(event) {
console.log('Button handler');
event.stopPropagation();
});
</script>
阻止剩下同事件+event.stopPropagation():event.stopImmediatePropagation()
如果多个事件监听器被附加到相同元素的相同事件类型上,当此事件触发时,它们会按其被添加的顺序被调用。
如果在其中一个事件监听器中执行 stopImmediatePropagation()
,那么剩下的事件监听器都不会被调用。
<button id="myButton">Click me</button>
<script>
const button = document.getElementById('myButton');
button.addEventListener('click', function(event) {
console.log('First handler');
event.stopImmediatePropagation();
});
button.addEventListener('click', function(event) {
console.log('Second handler');
});
button.addEventListener('click', function(event) {
console.log('Third handler');
});
</script>
默认行为(链接的跳转、表单的提交):event.preventDefault():
<a id="myLink" href="https://www.example.com">Click me</a>
<script>
const link = document.getElementById('myLink');
link.addEventListener('click', function(event) {
console.log('Link clicked');
event.preventDefault(); // 阻止链接的跳转
});
</script>
事件处理位置/DOM元素上的handler值
原生事件:事件处理函数
React:
nonp空函数
button
上绑定了两个事件
document
上的事件监听器,
button
,但是事件处理函数handle
,并不是我们的handerClick
事件,而是noop
事件被分解后绑定在document
onClick分解:click(事件类型)
onChange
分解:blur
,change
,input
,keydown
,keyup
将事件绑定在document
统一管理是为了跨浏览器包装
React17事件统一绑定container
ReactDOM.render(app, container);绑定在rootNode
因为微前端一个前端系统中可能有多个应用
事件保存在fiberNode对象的memoizedProps
和 pendingProps属性中
(React17取消)事件池:创建/回收->数组弹出
当事件被频繁的创建和回收,会影响性能
React事件池中事件并不会被释放,而是存入到一个数组中,如果这个事件触发,则直接在这个数组中弹出即可,这样就避免了频繁创建和销毁
但是对应的性能没有提高,所以就React17取消了事件池
1.事件注册(浏览器):初始化事件参数
1.事件合成:用插件机制 初始化事件参数+映射原生事件类型
2.事件绑定:注册监听器,绑定 dispatchEvent统一事件处理
scorll
,focus
,blur
等是在事件捕获阶段发生的,其他的都是在事件冒泡阶段发生的
3.事件触发:批量更新处理
Vue
与react区别:不暴露给开发者
绑定处理:模板和指令(@)
用法
区别 | 原生事件 | 合成事件 |
命名 | 纯小写onclick | 小驼峰onClick |
参数 | 字符串 | 函数 |
阻止默认事件 | e.preventDefault()和return false | e.preventDefault() |
事件源不同,阻止默认事件的方式不同,原生事件和合成事件的e.preventDefault()
并非是同一个函数
「react进阶」一文吃透react事件系统原理 - 掘金
合成事件 – React