欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

React合成事件原理及實現(React18和React16)

 更新時間:2025年02月27日 09:37:08   作者:不叫貓先生  
本文主要介紹了React合成事件原理及實現,包含React18和React16兩種版本,具有一定的參考價值,感興趣的可以了解一下

React中的合成事件絕對不是給當前元素基于addEventListener單獨做的事件綁定,而是基于事件委托處理的!

  • 在React17及以后版本,都是委托給#root這個容器「捕獲和冒泡都做了委托」;

  • 在React17以前的版本,都是為委托給document容器的「且只做了冒泡階段的委托」;

  • 對于沒有實現事件傳播機制的事件,才是單獨做的事件綁定「例如:onMouseEnter/onMouseLeave…」

    在組件渲染的時候,如果發(fā)現JSX元素屬性中有 onXxx/onXxxCapture 這樣的屬性,不會給當前元素直接做事件綁定,只是把綁定的方法賦值給元素的相關屬性
    例如:(onClick不是dom事件綁定,onclick才是事件綁定)

 outer.onClick=() => {console.log('outer 冒泡「合成」');}  //這不是DOM事件綁定「這樣的才是 outer.onclick」
 outer.onClickCapture=() => {console.log('outer 捕獲「合成」');}
 inner.onClick=() => {console.log('inner 冒泡「合成」');}
 inner.onClickCapture=() => {console.log('inner 捕獲「合成」');}

然后對#root這個容器做了事件綁定「捕獲和冒泡都做了」

組件中所渲染的內容,最后都會插入到#root容器中,這樣點擊頁面中任何一個元素,最后都會把#root的點擊行為觸發(fā)。而在給#root綁定的方法中,把之前給元素設置的onXxx/onXxxCapture屬性,在相應的階段執(zhí)行!!

React 18版本

React 合成事件事件傳播

 render() {
        return <div className="outer"
            onClick={() => {
                console.log('outer 冒泡「合成」');
            }}
            onClickCapture={() => {
                console.log('outer 捕獲「合成」');
            }}>

            <div className="inner"
                onClick={(ev) => {
                    // ev:合成事件對象
                    console.log('inner 冒泡「合成」', ev, ev.type);
                }}
                onClickCapture={() => {
                    console.log('inner 捕獲「合成」');
                }} 
            ></div>
        </div>;
    }

點擊inner元素之后

在這里插入圖片描述

在componentDidMount周期中,給元素綁定事件,可以看到此時已經“亂序”

 componentDidMount() {
        document.addEventListener('click', () => {
            console.log('document 捕獲');
        }, true);
        document.addEventListener('click', () => {
            console.log('document 冒泡');
        }, false);

        document.body.addEventListener('click', () => {
            console.log('body 捕獲');
        }, true);
        document.body.addEventListener('click', () => {
            console.log('body 冒泡');
        }, false);   
        let root = document.querySelector('#root');
        root.addEventListener('click', () => {
            console.log('root 捕獲');
        }, true);
        root.addEventListener('click', () => {
            console.log('root 冒泡');
        }, false); 
    }

在這里插入圖片描述

接著我們對inner、outer元素做事件綁定

  componentDidMount() {
        document.addEventListener('click', () => {
            console.log('document 捕獲');
        }, true);
        document.addEventListener('click', () => {
            console.log('document 冒泡');
        }, false);

        document.body.addEventListener('click', () => {
            console.log('body 捕獲');
        }, true);
        document.body.addEventListener('click', () => {
            console.log('body 冒泡');
        }, false);   

        let root = document.querySelector('#root');
        root.addEventListener('click', () => {
            console.log('root 捕獲');
        }, true);
        root.addEventListener('click', () => {
            console.log('root 冒泡');
        }, false);

        let outer = document.querySelector('.outer');
        outer.addEventListener('click', () => {
            console.log('outer 捕獲「原生」');
        }, true);
        outer.addEventListener('click', () => {
            console.log('outer 冒泡「原生」');
        }, false);

        let inner = document.querySelector('.inner');
        inner.addEventListener('click', () => {
            console.log('inner 捕獲「原生」');
        }, true);
        inner.addEventListener('click', (ev) => {
            // ev:原生事件對象
            // ev.stopPropagation();
            console.log('inner 冒泡「原生」');
        }, false);
    }

在這里插入圖片描述

React 合成事件原理

<script>
        const root = document.querySelector('#root'),
            outer = document.querySelector('#outer'),
            inner = document.querySelector('#inner');
        // 經過視圖渲染解析,outer/inner上都有onXxx/onXxxCapture這樣的屬性
        /* <div className="outer"
            onClick={() => { console.log('outer 冒泡「合成」'); }}
            onClickCapture={() => { console.log('outer 捕獲「合成」'); }}>
            <div className="inner"
                onClick={() => { console.log('inner 冒泡「合成」'); }}
                onClickCapture={() => { console.log('inner 捕獲「合成」'); }}
            ></div>
        </div>; */
        outer.onClick = () => { console.log('outer 冒泡「合成」'); }
        outer.onClickCapture = () => { console.log('outer 捕獲「合成」'); }
        inner.onClick = () => { console.log('inner 冒泡「合成」'); }
        inner.onClickCapture = () => { console.log('inner 捕獲「合成」'); }

        // 給#root做事件綁定
        root.addEventListener('click', (ev) => {
            let path = ev.path; // path:[事件源->....->window] 所有祖先元素
            [...path].reverse().forEach(ele => {
                let handle = ele.onClickCapture;
                if (handle) handle();
            });
        }, true);
        root.addEventListener('click', (ev) => {
            let path = ev.path;
            path.forEach(ele => {
                let handle = ele.onClick;
                if (handle) handle();
            });
        }, false);
    </script>

1、在視圖渲染時,遇到合成事件,并沒有給元素做事件綁定,而是給元素設置相對應的屬性,即合成屬性「 onXxx/onXxxCapture 

 <div className="outer"
            onClick={() => { console.log('outer 冒泡「合成」'); }}
            onClickCapture={() => { console.log('outer 捕獲「合成」'); }}>
            <div className="inner"
                onClick={() => { console.log('inner 冒泡「合成」'); }}
                onClickCapture={() => { console.log('inner 捕獲「合成」'); }}
            ></div>
        </div>; 

2、給#root做事件綁定,包括冒泡、捕獲,#root 上綁定的方法執(zhí)行,把所有規(guī)劃的路徑中,有合成事件屬性都執(zhí)行。
其中ev是原生事件對象

// 給#root做事件綁定
//捕獲階段 方法A
        root.addEventListener('click', (ev) => {
            let path = ev.composedPath(); // path:[事件源->....->window] 所有祖先元素
            [...path].reverse().forEach(ele => {
                let handle = ele.onClickCapture;
                if (handle) handle();
            });
        }, true);
//冒泡階段 方法B
        root.addEventListener('click', (ev) => {
            let path = ev.composedPath();
            path.forEach(ele => {
                let handle = ele.onClick;
                if (handle) handle();
            });
        }, false);

方法A,打印出path,事件源——>window

在這里插入圖片描述

方法B,打印出path,事件源——>window

在這里插入圖片描述

其中handle方法,具體的處理邏輯

const handleEv = function(ev){
    //ev 原生事件對象
     ......
    //返回  合成事件對象
}
//調用的時候
handleEv(ev)

其中在執(zhí)行綁定的合成事件handle()時

  • 如果不經過處理,方法中的thisundefined
  • 如果綁定的方法是箭頭函數,則找上級上下文中的this
  • 在執(zhí)行這些方法之前,會把原生對象ev做特殊處理,返回合成事件,傳遞給函數

在這里插入圖片描述

點擊inner元素的時候,按照原生的事件傳播機制

捕獲階段:

window捕獲、
document捕獲、
html捕獲
body捕獲
root捕獲 ->執(zhí)行:方法A
- window.onClickCapture (無)
- document.onClickCapture(無)
- html.onClickCapture(無)
- body.onClickCapture(無)
- root.onClickCapture(無)
- outer.onClickCapture => outer 捕獲「合成」
- inner.onClickCapture => inner 捕獲「合成」
outer 捕獲
innner 捕獲

冒泡階段:inner冒泡
outer冒泡
root冒泡->執(zhí)行:方法B
- inner.onClick = > inner 冒泡「合成」
- outer.onClick = > inner 冒泡「合成」
- body.onClick
- html.onClick
- document.onClick
- window.onClick

可以用圖來表示:

在這里插入圖片描述

React 合成事件中阻止事件傳播的影響

<div className="inner"
                onClick={(ev) => {
                    // ev:合成事件對象
                    console.log('inner 冒泡「合成」', ev, ev.type);
                    // ev.stopPropagation(); //合成事件對象中的“阻止事件傳播”:阻止原生的事件傳播 & 阻止合成事件中的事件傳播
                    // ev.nativeEvent.stopPropagation(); //原生事件對象中的“阻止事件傳播”:只能阻止原生事件的傳播
                    // ev.nativeEvent.stopImmediatePropagation(); //原生事件對象的阻止事件傳播,只不過可以阻止#root上其它綁定的方法執(zhí)行

                    /* setTimeout(() => {
                        console.log(ev, ev.type); //React18中并沒有事件對象池機制,所以也不存在:創(chuàng)建的事件對象信息清空問題!!
                    }, 500); */ 
                }}
                onClickCapture={() => {
                    console.log('inner 捕獲「合成」');
                }}

合成事件stopPropagation

首先 ev.stopPropagation(),合成事件對象中的“阻止事件傳播”:阻止原生的事件傳播& 阻止合成事件中的事件傳播。

在這里插入圖片描述

合成事件nativeEvent.stopPropagation

ev.nativeEvent.stopPropagation:原生事件對象中的“阻止事件傳播”:只能阻止原生事件的傳播。

在這里插入圖片描述

合成事件nativeEvent.stopImmediatePropagation

ev.nativeEvent.stopImmediatePropagation :原生事件對象的阻止事件傳播,只不過可以阻止#root上其他綁定的方法執(zhí)行,此時root冒泡就沒了

在這里插入圖片描述

原生stopPropagation

inner.addEventListener('click', (ev) => {
            // ev:原生事件對象
            ev.stopPropagation();
            console.log('inner 冒泡「原生」');
        }, false);

在這里插入圖片描述

React 16版本

合成事件原理

16版本中,合成事件的處理機制不再把事件委托給root元素,而是委托給document元素;并且只做了冒泡階段的委托;在委托的方法中,把onXxx/onXxxCapture合成事件屬性執(zhí)行。

在這里插入圖片描述

點擊inner元素之后,打印結果

在這里插入圖片描述

1、對視圖進行解析
給元素添加合成事件元素,并不是直接做事件綁定

outer.onClick = ()=>{...}
outer.onClickCapture = ()=>{...}
inner.onClick = ()=>{...}
innner.onClickCapture = ()=>{...}

2、對document的冒泡階段做了事件委托

document.addEventListener("click",(ev)=>{
    //ev:原生事件對象
    let path = ev.composedPath();//傳播路徑:[事件源-> window];
    let syntheticEv=處理事件對象(ev)
    //把捕獲階段的合成事件執(zhí)行
    [...path].reverse().forEach(ele=>{
           let handle = ele.onClickCapture;
           if(handle) handle(syntheticEv)
    })
    //把冒泡階段的合成事件執(zhí)行
    path.forEach(ele=>{
           let handle = ele.onClick;
           if(handle) handle(syntheticEv)
      }) 
})

在這里插入圖片描述

合成事件中阻止事件傳播的影響

<div className="inner"
                onClick={(ev) => {
                    // ev:合成事件對象
                    console.log('inner 冒泡「合成」', ev, ev.type);
                    // ev.stopPropagation(); //合成事件對象中的“阻止事件傳播”:阻止原生的事件傳播 & 阻止合成事件中的事件傳播
                    // ev.nativeEvent.stopPropagation(); //原生事件對象中的“阻止事件傳播”:只能阻止原生事件的傳播
                    // ev.nativeEvent.stopImmediatePropagation(); //原生事件對象的阻止事件傳播,只不過可以阻止#root上其它綁定的方法執(zhí)行

                    /* setTimeout(() => {
                        console.log(ev, ev.type); //React18中并沒有事件對象池機制,所以也不存在:創(chuàng)建的事件對象信息清空問題?。?
                    }, 500); */ 
                }}
                onClickCapture={() => {
                    console.log('inner 捕獲「合成」');
                }}
 </div>               

合成事件stopPropagation()

在這里插入圖片描述

合成事件nativeEvent.stopPropagation()

在這里插入圖片描述

合成事件nativeEvent.stopImmediatePropagation()

在這里插入圖片描述

原生事件stopPropagation

inner.addEventListener('click', (ev) => {
            // ev:原生事件對象
            ev.stopPropagation();
            console.log('inner 冒泡「原生」');
        }, false);

在這里插入圖片描述

事件對象池

React 16中,關于合成事件對象的處理,React內部是基于“事件對象池”,做了一個緩存機制。

React 17及以后,是去掉了這套事件對象池和緩存機制

  • 當每一次事件觸發(fā)的時候,如果傳播到了委托的元素上「document/#root」,在委托的方法中,首先會對內置事件對象做統(tǒng)一處理,生成合成事件對象

React 16 版本中:

為了防止每一次都是重新創(chuàng)建出新的合成事件對象,它設置了一個事件對象池「緩存池」

  • 本次事件觸發(fā),獲取到事件操作的相關信息后,從 事件對象池 中獲取存儲的合成事件對象,把信息賦值給相關的成員
  • 等待本次操作結束,把合成事件對象中的成員信息都清空掉,再放入到「事件對象池」中

在這里插入圖片描述

<div className="inner"
                onClick={(ev) => {
                    // ev:合成事件對象
                    console.log('inner 冒泡「合成」', ev, ev.type);

                    setTimeout(() => {
                        console.log(ev, ev.type); //React18中并沒有事件對象池機制,所以也不存在:創(chuàng)建的事件對象信息清空問題!!
                    }, 500); 
                }}
                onClickCapture={() => {
                    console.log('inner 捕獲「合成」', ev, ev.type);
                }}
    ></div>

500ms之后,合成事件對象還在,但是里面的成員信息都被清空了

在這里插入圖片描述

在React 18 中,并沒有事件對象池機制,所以不存在創(chuàng)建的事件對象信息清空的問題。但是React 合成事件中 ev.persist() 可以把合成事件對象中的信息保留下來。

到此這篇關于React合成事件原理及實現(React18和React16)的文章就介紹到這了,更多相關React合成事件內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • React中Key屬性作用

    React中Key屬性作用

    react中的key屬性,它是一個特殊的屬性,它是出現不是給開發(fā)者用的,而是給React自己使用,有了key屬性后,就可以與組件建立了一種對應關系,本文主要介紹了React中Key屬性作用,具有一定的參考價值,感興趣的可以了解一下
    2024-01-01
  • React報錯Element type is invalid解決案例

    React報錯Element type is invalid解決案例

    這篇文章主要為大家介紹了React報錯Element type is invalid解決案例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-12-12
  • react框架next.js學習之API?路由篇詳解

    react框架next.js學習之API?路由篇詳解

    這篇文章主要為大家介紹了react框架next.js學習之API?路由篇詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-09-09
  • React18?useState何時執(zhí)行更新及微任務理解

    React18?useState何時執(zhí)行更新及微任務理解

    這篇文章主要為大家介紹了React18?useState何時執(zhí)行更新及微任務理解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-11-11
  • Remix 后臺桌面開發(fā)electron-remix-antd-admin

    Remix 后臺桌面開發(fā)electron-remix-antd-admin

    這篇文章主要為大家介紹了Remix 后臺桌面開發(fā)electron-remix-antd-admin的過程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-04-04
  • React中useEffect原理的代碼簡單實現詳解

    React中useEffect原理的代碼簡單實現詳解

    React的useEffect鉤子是React函數組件中處理副作用,本文將通過一個簡單的例子解釋如何用代碼實現useEffect的基本原理,感興趣的小伙伴可以了解下
    2023-12-12
  • react-redux的connect用法詳解

    react-redux的connect用法詳解

    react-redux是react官方推出的redux綁定庫,React-Redux 將所有組件分成兩大類一個是UI組件和容器組件,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2023-01-01
  • React函數式組件與類組件的不同你知道嗎

    React函數式組件與類組件的不同你知道嗎

    這篇文章主要為大家詳細介紹了React函數式組件與類組件的不同,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03
  • React Fiber中面試官最關心的技術話題

    React Fiber中面試官最關心的技術話題

    這篇文章主要為大家介紹了React Fiber中面試官最關心的技術話題解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-06-06
  • React中引入less、less-loader問題

    React中引入less、less-loader問題

    這篇文章主要介紹了React中引入less、less-loader問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01

最新評論