逼逼叨React事件

178 阅读2分钟

一、DOM事件流分为三个阶段

1.事件捕获阶段

当某个事件触发时,文档根节点最先接收到事件,然后根据DOM树结构向具体绑定事件的元素传递,从父元素向子元素传递,该阶段为捕获阶段。
window ->document -> body -> div

2.目标阶段

事件苑已经捕获事件,开始向外冒泡。

3.事件冒泡阶段

根据DOM结构由触发事件的元素向根节点传递,称为冒泡阶段。
div -> body -> document -> window

二、原生DOM注册监听事件

使用addEventListener函数为DOM元素注册监听事件
DOMElement.addEventListener('事件名称',Fn,useCapture),useCapture时在捕获阶段监听事件;为false时,在冒泡阶段监听事件。默认为false。

三、原生事件委托

<div>
    <ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
    </ul>
</div>

const click = document.querySelector("ul").addEventListener("click",function(e){ 
    console.log("asdasda");
},true);  

假设我们想要在每个 li 上绑定 click 事件,可以直接给每个 li 添加点击事件,增加事件回调。有一种更好的做法,那就是在 ul 上添加一个监听事件,由于事件的冒泡机制,事件就会冒泡到ul上,因为ul上有事件监听,所以事件就会触发。这就是事件委托。

四、React合成事件

和原生DOM的事件都是绑定在真实DOM元素上不同的就是React中就是用了这种事件委托的方法,将所有事件都绑定在document 这个节点上,document监听事件的变化。故只有document这个节点上面才绑定了DOM原生事件。

<div onClick={handleClick}>
	<DropDown />
</div>
const handleClick = (e) => {
	e.stopPropagation()
}

如上,和原生DOM不同,React通过驼峰式的命名方法来绑定事件,这叫合成事件

来个栗子:

const Test = () => {
  useEffect(() => {
    document.addEventListener('click', function(){
      console.log('document click')
    })
    document.getElementsByClassName('App')[0].addEventListener('click', function(){
      console.log('app click')
    })
    document.getElementsByClassName('Btn')[0].addEventListener('click', function(e){
      console.log('button click')
      // e.stopPropagation();
    })
  },[])
    
  onClick = (e) => {
    e.stopPropagation() // 能够阻止div.app的触发
    e.nativeEvent.stopImmediatePropagation(); // 能够阻止document的触发
    e.nativeEvent.stopPropagation(); // 什么都阻止不了
    console.log('react button click');
  }
  return (
    <div className="App" onClick={() => {console.log('react app click')}}>
      <Button className="Btn" onClick={this.onClick}>点我</Button>
    </div>
  )BBtn
}
【结果是------------------------------】
button click
app click
react button click
react app click
document click

五、React中阻止冒泡

A、只阻止React合成事件间的冒泡,用e.stopPropagation()

【栗子结果】
button click
app click
react button click
document click

B、阻止React合成事件和document的冒泡,用e.nativeEvent.stopImmediatePropagation()

【栗子结果】
button click
app click
react button click
react app click

C、阻止合成事件与非合成事件(除document)的冒泡,用e.target判断

e.target && e.target === document.querySelector('#inner')
e.target.NodeName

D、e.native.stopPropagation 什么都阻止不了

【栗子结果】
button click
app click
react button click
react app click
document click

六、javascript中不会冒泡的事件

  • scroll
  • focus & blur
  • Media事件(onplay、onpause...)
  • mouseleave & mouseenter 这些不会冒泡的事件自然就不用阻止冒泡,e.stopPropagation()无效。
    在事件委托时,要注意在捕获阶段进行监听,否则事件会失效