this
React
事件和原生事件有什麼區別React
事件和原生事件的執行順序,能夠混用嗎React
事件如何解決跨瀏覽器兼容下面是我閱讀過源碼後,將全部的執行流程總結出來的流程圖,不會貼代碼,若是你想閱讀代碼看看具體是如何實現的,能夠根據流程圖去源碼裏尋找。node
lastProps
、nextProps
判斷是否新增、刪除事件分別調用事件註冊、卸載方法。EventPluginHub
的enqueuePutListener
進行事件存儲document
對象。onClick
、onCaptureClick
)判斷是進行冒泡仍是捕獲。addEventListener
方法,不然使用attachEvent
(兼容IE)。document
註冊原生事件回調爲dispatchEvent
(統一的事件分發機制)。EventPluginHub
負責管理React合成事件的callback
,它將callback
存儲在listenerBank
中,另外還存儲了負責合成事件的Plugin
。EventPluginHub
的putListener
方法是向存儲容器中增長一個listener。key
。callback
根據事件類型,元素的惟一標識key
存儲在listenerBank
中。listenerBank
的結構是:listenerBank[registrationName][key]
。例如:react
{ onClick:{ nodeid1:()=>{...} nodeid2:()=>{...} }, onChange:{ nodeid3:()=>{...} nodeid4:()=>{...} } }
這裏的事件執行利用了React
的批處理機制,在前一篇的【React深刻】setState執行機制中已經分析過,這裏再也不多加分析。segmentfault
document
註冊原生事件的回調dispatchEvent
例以下面的代碼:首先會獲取到this.child
瀏覽器
<div onClick={this.parentClick} ref={ref => this.parent = ref}> <div onClick={this.childClick} ref={ref => this.child = ref}> test </div> </div>
eventQueue
事件隊列中。eventQueue
。isPropagationStopped
判斷當前事件是否執行了阻止冒泡方法。executeDispatch
執行合成事件。react
在本身的合成事件中重寫了stopPropagation
方法,將isPropagationStopped
設置爲true
,而後在遍歷每一級事件的過程當中根據此遍歷判斷是否繼續執行。這就是react
本身實現的冒泡機制。babel
EventPluginHub
的extractEvents
方法。EventPlugin
(用來處理不一樣事件的工具方法)。EventPlugin
中根據不一樣的事件類型,返回不一樣的事件池。nodeid
(惟一標識key
)和事件類型從listenerBink
中取出回調函數將上面的四個流程串聯起來。dom
經過事件觸發過程的分析,dispatchEvent
調用了invokeGuardedCallback
方法。函數
function invokeGuardedCallback(name, func, a) { try { func(a); } catch (x) { if (caughtError === null) { caughtError = x; } } }
可見,回調函數是直接調用調用的,並無指定調用的組件,因此不進行手動綁定的狀況下直接獲取到的this
是undefined
。工具
這裏可使用實驗性的屬性初始化語法 ,也就是直接在組件聲明箭頭函數。箭頭函數不會建立本身的this
,它只會從本身的做用域鏈的上一層繼承this
。所以這樣咱們在React
事件中獲取到的就是組件自己了。this
React
事件使用駝峯命名,而不是所有小寫。JSX
, 你傳遞一個函數做爲事件處理程序,而不是一個字符串。例如,HTML
:spa
<button onclick="activateLasers()"> Activate Lasers </button>
在 React
中略有不一樣:
<button onClick={activateLasers}> Activate Lasers </button>
另外一個區別是,在 React 中你不能經過返回 false
來阻止默認行爲。必須明確調用 preventDefault
。
由上面執行機制咱們能夠得出:React
本身實現了一套事件機制,本身模擬了事件冒泡和捕獲的過程,採用了事件代理,批量更新等方法,而且抹平了各個瀏覽器的兼容性問題。
React
事件和原生事件的執行順序componentDidMount() { this.parent.addEventListener('click', (e) => { console.log('dom parent'); }) this.child.addEventListener('click', (e) => { console.log('dom child'); }) document.addEventListener('click', (e) => { console.log('document'); }) } childClick = (e) => { console.log('react child'); } parentClick = (e) => { console.log('react parent'); } render() { return ( <div onClick={this.parentClick} ref={ref => this.parent = ref}> <div onClick={this.childClick} ref={ref => this.child = ref}> test </div> </div>) }
執行結果:
由上面的流程咱們能夠理解:
react
的全部事件都掛載在document
中document
後纔會對react
事件進行處理react
合成事件document
上掛載的事件react
事件和原生事件最好不要混用。
原生事件中若是執行了stopPropagation
方法,則會致使其餘react
事件失效。由於全部元素的事件將沒法冒泡到document
上。
由上面的執行機制不可貴出,全部的react事件都將沒法被註冊。
function handleClick(e) { e.preventDefault(); console.log('The link was clicked.'); }
這裏,e
是一個合成的事件。React
根據 W3C 規範 定義了這個合成事件,因此你不須要擔憂跨瀏覽器的兼容性問題。
事件處理程序將傳遞 SyntheticEvent
的實例,這是一個跨瀏覽器原生事件包裝器。 它具備與瀏覽器原生事件相同的接口,包括 stopPropagation()
和 preventDefault()
,在全部瀏覽器中他們工做方式都相同。
每一個 SyntheticEvent
對象都具備如下屬性:
boolean bubbles boolean cancelable DOMEventTarget currentTarget boolean defaultPrevented number eventPhase boolean isTrusted DOMEvent nativeEvent void preventDefault() boolean isDefaultPrevented() void stopPropagation() boolean isPropagationStopped() DOMEventTarget target number timeStamp string type
React
合成的SyntheticEvent
採用了事件池,這樣作能夠大大節省內存,而不會頻繁的建立和銷燬事件對象。
另外,無論在什麼瀏覽器環境下,瀏覽器會將該事件類型統一建立爲合成事件,從而達到了瀏覽器兼容的目的。