摘要:組件事件響應(yīng)在構(gòu)建虛擬的同時,還構(gòu)建了自己的事件系統(tǒng)且所有事件對象和規(guī)范保持一致。的事件系統(tǒng)和瀏覽器事件系統(tǒng)相比,主要增加了兩個特性事件代理和事件自動綁定。
React組件事件響應(yīng)
React在構(gòu)建虛擬DOM的同時,還構(gòu)建了自己的事件系統(tǒng);且所有事件對象和W3C規(guī)范
保持一致。
React的事件系統(tǒng)和瀏覽器事件系統(tǒng)相比,主要增加了兩個特性:事件代理、和事件自動綁定。
1、事件代理區(qū)別于瀏覽器事件處理方式,React并未將事件處理函數(shù)與對應(yīng)的DOM節(jié)點(diǎn)直接關(guān)聯(lián),而是在頂層使用
了一個全局事件監(jiān)聽器監(jiān)聽所有的事件;
React會在內(nèi)部維護(hù)一個映射表記錄事件與組件事件處理函數(shù)的對應(yīng)關(guān)系;
當(dāng)某個事件觸發(fā)時,React根據(jù)這個內(nèi)部映射表將事件分派給指定的事件處理函數(shù);
當(dāng)映射表中沒有事件處理函數(shù)時,React不做任何操作;
當(dāng)一個組件安裝或者卸載時,相應(yīng)的事件處理函數(shù)會自動被添加到事件監(jiān)聽器的內(nèi)部映射表中或從表中刪除。
2、事件自動綁定在JavaScript中創(chuàng)建回調(diào)函數(shù)時,一般要將方法綁定到特定的實(shí)例,以保證this的正確性;
2.在React中,每個事件處理回調(diào)函數(shù)都會自動綁定到組件實(shí)例(使用ES6語法創(chuàng)建的例外);
注意:事件的回調(diào)函數(shù)被綁定在React組件上,而不是原始的元素上,即事件回調(diào)函數(shù)中的
this所指的是組件實(shí)例而不是DOM元素;
了解更多React中的thisReact組件中的this。
3、合成事件與瀏覽器事件處理稍微有不同的是,React中的事件處理程序所接收的事件參數(shù)是被稱為“合成事件(SyntheticEvent)”的實(shí)例。
合成事件是對瀏覽器原生事件跨瀏覽器的封裝,并與瀏覽器原生事件有著同樣的接口,如stopPropagation(),preventDefault()等,并且
這些接口是跨瀏覽器兼容的。
如果需要使用瀏覽器原生事件,可以通過合成事件的nativeEvent屬性獲取
React合成事件原理
使用JSX,在React中綁定事件:
React并不是將click事件綁在該div的真實(shí)DOM上,而是在document處監(jiān)聽所有支持的事件,當(dāng)事件發(fā)生并冒泡至document處時,React將事件內(nèi)容封裝并交由真正的處理函數(shù)運(yùn)行
每個合成事件有以下通用屬性:
- 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
注意:現(xiàn)版本React在事件處理程序通過中返回false停止傳播,已不可用;
取而代之的是需要手動調(diào)用e.stopPropagation()或e.preventDefalult().
onCopy onCut onPaste
2、鍵盤事件onKeyDown onKeyPress onKeyUp
3、焦點(diǎn)事件onFocus onBlur
這些焦點(diǎn)事件工作在 React DOM 中所有的元素上 ,不僅是表單元素。
4、表單事件onChange onInput onSubmit
onChange事件經(jīng)過React改良,內(nèi)容改變時即可實(shí)時觸發(fā);而原生的需內(nèi)容改變且失去焦點(diǎn)后觸發(fā)才觸發(fā)。
5、鼠標(biāo)事件onClick onContextMenu onDoubleClick onDrag onDragEnd onDragEnter onDragExit onDragLeave onDragOver onDragStart onDrop onMouseDown onMouseEnter onMouseLeave onMouseMove onMouseOut onMouseOver onMouseUp
onMouseEnter 和 onMouseLeave 事件從離開的元素傳播到正在進(jìn)入的元素,而不是普通的冒泡,并且沒有捕獲階段;只有在鼠標(biāo)指針穿過被選元素時,才會觸發(fā)。
onMouseOut onMouseOver事件:不論鼠標(biāo)指針穿過被選元素或其子元素,都會觸發(fā)。
6、選擇事件onSelect
7、觸摸事件onTouchCancel onTouchEnd onTouchMove onTouchStart
8、UI事件onScroll
9、滾輪事件onWheel
10、圖像事件onLoad onError
11、動畫事件onAnimationStart onAnimationEnd onAnimationIteration
12、其他事件onToggle
在React中使用原生事件由于原生事件需要綁定在真實(shí)DOM上,所以一般是在 componentDidMount階段/ref的函數(shù)執(zhí)行階段進(jìn)行綁定操作,在componentWillUnmount 階段進(jìn)行解綁操作以避免內(nèi)存泄漏。
import React,{Component} from "react"; import ReactDOM from "react-dom" class ReactEvent extends Component { componentDidMount() { //獲取當(dāng)前真實(shí)DOM元素 const thisDOM = ReactDOM.findDOMNode(this); thisDOM.addEventListener("click",this.onDOMClick,false); } componentWillUnmount() { //卸載時解綁事件,防止內(nèi)存泄漏 const thisDOM = ReactDOM.findDOMNode(this); thisDOM.removeEventListener("click",this.removeDOMClick); } onDOMClick(e){ console.log(e) } render(){ return(合成事件和原生事件混合使用單擊原始事件觸發(fā)) } } export default ReactEvent
響應(yīng)順序
import React,{Component} from "react"; import ReactDOM from "react-dom" class ReactEvent extends Component { constructor(props){ super(props) this.state = { value: "" } this.onReactClick = this.onReactClick.bind(this) } componentDidMount() { //獲取當(dāng)前真實(shí)DOM元素 const thisDOM = ReactDOM.findDOMNode(this); thisDOM.addEventListener("click",this.onDOMClick,false); } componentWillUnmount() { //卸載時解綁事件,防止內(nèi)存泄漏 const thisDOM = ReactDOM.findDOMNode(this); thisDOM.removeEventListener("click",this.removeDOMClick); } onDOMClick(e){ console.log("原生事件綁定事件觸發(fā)") } onReactClick(e){ console.log("React合成事件綁定事件觸發(fā)") } render(){ return(單擊事件觸發(fā)) } } export default ReactEvent
首先DOM事件監(jiān)聽器被執(zhí)行,然后事件繼續(xù)冒泡至document,合成事件監(jiān)聽器再被執(zhí)行。
即,最終控制臺輸出為:
原生事件綁定事件觸發(fā)
合成事件綁定事件觸發(fā)
阻止冒泡
如果在onDOMClick中調(diào)用e.stopPropagtion()
onDOMClick(e){ e.stopPropagation() console.log("原生事件綁定事件觸發(fā)") }
由于DOM事件被阻止冒泡了,無法到達(dá)document,所以合成事件自然不會被觸發(fā),控制臺輸出就變成了:
原生事件綁定事件觸發(fā)
再測試個復(fù)雜的例子
import React,{Component} from "react"; import ReactDOM from "react-dom" class ReactEvent extends Component { constructor(props){ super(props) this.state = { value: "" } this.onReactClick = this.onReactClick.bind(this) this.onReactChildClick = this.onReactChildClick.bind(this) } componentDidMount() { //獲取當(dāng)前真實(shí)DOM元素 const thisDOM = ReactDOM.findDOMNode(this); thisDOM.addEventListener("click",this.onDOMClick,false); //獲取子元素并綁定事件 const thisDOMChild = thisDOM.querySelector(".child"); thisDOMChild.addEventListener("click",this.onDOMChildClick,false); } onDOMClick(e){ console.log("父組件原生事件綁定事件觸發(fā)") } onReactClick(e){ console.log("父組件React合成事件綁定事件觸發(fā)") } onDOMChildClick(e){ e.stopPropagation() console.log("子元素原生事件綁定事件觸發(fā)") } onReactChildClick(e){ console.log("子元素React合成事件綁定事件觸發(fā)") } render(){ return(父元素單擊事件觸發(fā)) } } export default ReactEvent
通過設(shè)置原生事件綁定為冒泡階段調(diào)用,且每次測試單擊子元素按鈕:
在子元素原生事件程序中阻止事件傳播,則打印出:
子元素原生事件綁定事件觸發(fā);
在父元素元素事件程序中阻止事件傳播,則打印出:
子元素原生事件綁定事件觸發(fā)
父組件原生事件綁定事件觸發(fā)
在子元素React合成事件onClick中阻止事件傳播,則打印出:
子元素原生事件綁定事件觸發(fā)
父組件原生事件綁定事件觸發(fā)
子元素React合成事件綁定事件觸發(fā)
在父元素React合成事件onClick中阻止事件傳播,則打印出:
子元素原生事件綁定事件觸發(fā)
父組件原生事件綁定事件觸發(fā)
子元素React合成事件綁定事件觸發(fā)
父組件React合成事件綁定事件觸發(fā)
可以看到若不阻止事件傳播每次(單擊子元素)事件觸發(fā)流程是:
Document->子元素(原生事件觸發(fā))->父元素(原生事件)->回到Document->React子元素合成事件監(jiān)聽器觸發(fā) ->React父元素合成事件監(jiān)聽器觸發(fā)
其實(shí),React合成事件封裝的stopPropagtion函數(shù)在調(diào)用時給自己加了個isPropagationStopped的標(biāo)記位來確定后續(xù)監(jiān)聽器是否執(zhí)行。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/93282.html
摘要:系列種優(yōu)化頁面加載速度的方法隨筆分類中個最重要的技術(shù)點(diǎn)常用整理網(wǎng)頁性能管理詳解離線緩存簡介系列編寫高性能有趣的原生數(shù)組函數(shù)數(shù)據(jù)訪問性能優(yōu)化方案實(shí)現(xiàn)的大排序算法一怪對象常用方法函數(shù)收集數(shù)組的操作面向?qū)ο蠛驮屠^承中關(guān)鍵詞的優(yōu)雅解釋淺談系列 H5系列 10種優(yōu)化頁面加載速度的方法 隨筆分類 - HTML5 HTML5中40個最重要的技術(shù)點(diǎn) 常用meta整理 網(wǎng)頁性能管理詳解 HTML5 ...
摘要:系列種優(yōu)化頁面加載速度的方法隨筆分類中個最重要的技術(shù)點(diǎn)常用整理網(wǎng)頁性能管理詳解離線緩存簡介系列編寫高性能有趣的原生數(shù)組函數(shù)數(shù)據(jù)訪問性能優(yōu)化方案實(shí)現(xiàn)的大排序算法一怪對象常用方法函數(shù)收集數(shù)組的操作面向?qū)ο蠛驮屠^承中關(guān)鍵詞的優(yōu)雅解釋淺談系列 H5系列 10種優(yōu)化頁面加載速度的方法 隨筆分類 - HTML5 HTML5中40個最重要的技術(shù)點(diǎn) 常用meta整理 網(wǎng)頁性能管理詳解 HTML5 ...
摘要:導(dǎo)航組件使用詳解注意了,如果有小伙伴們發(fā)現(xiàn)運(yùn)行作者提供的示例項(xiàng)目報(bào)如下的錯誤,可能是大家使用了命令導(dǎo)致的,解決這個錯誤的辦法就是將刪除,然后重新使用命令來安裝,最后使用來起服務(wù),應(yīng)該就不報(bào)錯了。 react-navigation導(dǎo)航組件使用詳解 注意了,如果有小伙伴們發(fā)現(xiàn)運(yùn)行作者提供的react-navigation示例項(xiàng)目報(bào)如下的錯誤,可能是大家使用了 yarn install 命...
本文主要講述ref 的應(yīng)用僅為父組件調(diào)用子組件場景下的應(yīng)用方式1 Class組件 1. 自定義事件 Parent.js importReact,{Component}from'react'; importChildfrom'./Child'; classParentextendsComponent{ componentDidMount(){ ...
閱讀 1612·2021-11-23 09:51
閱讀 1183·2019-08-30 13:57
閱讀 2263·2019-08-29 13:12
閱讀 2017·2019-08-26 13:57
閱讀 1201·2019-08-26 11:32
閱讀 981·2019-08-23 15:08
閱讀 707·2019-08-23 14:42
閱讀 3087·2019-08-23 11:41