一、了解DOM事件流
事件流分为3个阶段
1. 事件捕获阶段:例如点击button,会先捕获body, 然后父元素div,button
2. 处于目标阶段:在button节点上触发
3. 事件冒泡阶段:事件从button冒泡到body-document
<body>
<div>
<button onclick="handleclick()"></button>
</div>
</body>
任何事件都是按照次顺序,可以选择在捕获阶段还是冒泡阶段绑定事件处理机制。
element.addEventListener(event, function, flag)
flag为 true,则在捕获阶段绑定;flag为false,则在冒泡阶段绑定事件
二、阻止冒泡
IE: window.event.cancelBubble = true;
W3C :event.stopPropagation()
三、事件代理
又称事件委托,将原本需要绑定在子元素上的事件绑定到父元素身上,让父元素监听,运用 事件冒泡的原理,可以节约内存,减少事件注册,React合成事件使用此方式
四、React事件机制
合成事件:是跨浏览器原生事件的一个包装器,将不同浏览器的行为根据W3C规范合并为一个API,为了确保事件在不同浏览器中显示一致的属性 。
class TestComponent extends React.Component{
constructor(props){
super(props)
this.state = {
username: 'cache'
}
this.parentRef = React.createRef()
this.childRef = React.createRef()
}
componentDidMount(){
this.parentRef.current.addEventListener('click', ()=>{
console.1og(“父元素原生事件捕获”)
}, true)
this.parentRef.current.addEventListener('click', ()=>{
console.1og(“父元素原生事件冒泡”)
}, false)
this.childRef.current.addEventListener('click', ()=>{
console.1og(“子元素原生事件捕获”)
}, true)
this.childRef.current.addEventListener('click', ()=>{
console.1og(“子元素原生事件冒泡”)
}, false)
document.addEventListener('click', ()=>{
console.1og(“document原生事件捕获”)
}, true)
document.addEventListener('click', ()=>{
console.1og(“document原生事件冒泡”)
}, false)
}
parentBubble =()=>{
console.log('父元素React冒泡事件')
}
panentCapture =()=>{
console.log('父元素React捕获事件')
}
childBubble =()=>{
console.log('子元素React冒泡事件')
}
childCapture =()=>{
console.log('子元素React捕获事件')
}
render(){
return <div ref={this.parentRef} onClick={this.parentBubble} onClickCapture={this.panentCapture}>
<button ref={this.childRef} onClick={this.childBubble} onClickCapture={this.childCapture}>Test</button>
</div>
}
}
以上执行顺序:
document原生事件捕获;
父元素React捕获事件;
子元素React捕获事件;
父元素原生事件捕获;
子元素原生事件捕获;
子元素原生事件冒泡;
父元素原生事件冒泡;
子元素React冒泡事件;
父元素React冒泡事件;
document原生事件冒泡;
document原生事件捕获;
为什么先捕获React事件?
因为react事件是统一代理到#root或者document上,react应用一进去先注册,注册的早捕获的就早,所以会比原生事件先捕获到。
如果在某个阶段阻止事件传播,后面的事件都不走了?
是的 ,每个事件执行都遵循事件流顺序 ,一但阻止,后续都不执行。
阻止合成事件也会阻止原生事件吗?
是的。