這篇文章要跟大家介紹的內容是關於React Event事件註冊的實現,有著一定的參考價值,有需要的朋友可以參考一下。
React 元素的事件處理和 DOM元素的很相似。但是有一點語法上的不同:
React事件綁定屬性的命名採用駝峰式寫法,而不是小寫。
如果採用JSX 的語法你需要傳入一個函數作為事件處理函數,而不是一個字串(DOM元素的寫法)
並且React 自己內部實作了一個合成事件,使用React 的時候通常你不需要使用addEventListener 為一個已建立的DOM 元素加入監聽器。你僅僅需要在這個元素初始渲染的時候提供一個監聽器。
我們看一下這是怎麼實現的
React 事件機制分為事件註冊,和事件分發,兩個部分
// 事件绑定 function handleClick(e) { e.preventDefault(); console.log('The link was clicked.'); } return ( <a> Click me </a> );
上述程式碼中,onClick 作為一個props 傳入了一個handleClick,在元件更新和掛載的時候,會對props處理, 流程如下:
#核心程式碼:
在ReactDOMComponent.js 進行元件載入(mountComponent)、更新(updateComponent) 的時候,呼叫_updateDOMProperties
方法對props 進行處理:
_updateDOMProperties: function(lastProps, nextProps, transaction) { ... if (registrationNameModules.hasOwnProperty(propKey)) { if (nextProp) { // 如果传入的是事件,去注册事件 enqueuePutListener(this, propKey, nextProp, transaction); } else if (lastProp) { deleteListener(this, propKey); } } ... } // 注册事件 function enqueuePutListener(inst, registrationName, listener, transaction) { var containerInfo = inst._nativeContainerInfo; var doc = containerInfo._ownerDocument; ... // 去doc上注册 listenTo(registrationName, doc); // 事务结束之后 putListener transaction.getReactMountReady().enqueue(putListener, { inst: inst, registrationName: registrationName, listener: listener, }); }
看下綁定方法
listento
//registrationName:需要绑定的事件 //当前component所属的document,即事件需要绑定的位置 listenTo: function (registrationName, contentDocumentHandle) { var mountAt = contentDocumentHandle; //获取当前document上已经绑定的事件 var isListening = getListeningForDocument(mountAt); ... if (...) { //冒泡处理 ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(...); } else if (...) { //捕捉处理 ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(...); } ... },
走到最後其實就是doc.addEventLister(event, callback, false);
可以看出所有事件綁定在document上
所以事件觸發的都是ReactEventListener的dispatchEvent方法
react 維護了一個listenerBank 的變數保存了所有的綁定事件的回呼。
回到之前註冊事件的方法
function enqueuePutListener(inst, registrationName, listener, transaction) { var containerInfo = inst._nativeContainerInfo; var doc = containerInfo._ownerDocument; if (!doc) { // Server rendering. return; } listenTo(registrationName, doc); transaction.getReactMountReady().enqueue(putListener, { inst: inst, registrationName: registrationName, listener: listener, }); }
當綁定完成以後會執行putListener。
var listenerBank = {}; var getDictionaryKey = function (inst) { //inst为组建的实例化对象 //_rootNodeID为组件的唯一标识 return '.' + inst._rootNodeID; } var EventPluginHub = { //inst为组建的实例化对象 //registrationName为事件名称 //listner为我们写的回调函数,也就是列子中的this.autoFocus putListener: function (inst, registrationName, listener) { ... var key = getDictionaryKey(inst); var bankForRegistrationName = listenerBank[registrationName] || (listenerBank[registrationName] = {}); bankForRegistrationName[key] = listener; ... } }
EventPluginHub在每個React中只會實例化一次。也就是說,項目組所有事件的回呼都會儲存在唯一的listenerBank。
相關推薦:
以上是React Event事件註冊的實現的詳細內容。更多資訊請關注PHP中文網其他相關文章!