Draft 事件處理機(jī)制
Draft.js 內(nèi)部封裝了一系列基礎(chǔ)的事件處理函數(shù)屎鳍,當(dāng)事件觸發(fā)時(shí),這些函數(shù)接收當(dāng)前event
,并基于此生成new editorState
垛吗,我們?cè)诮邮盏?code>new editorState后再將該數(shù)據(jù)綁定到Draft
上,這就是Draft的單向數(shù)據(jù)流烁登。其中react
層只負(fù)責(zé)視圖層怯屉,我們將通過一些流程圖與源碼的展示來詳細(xì)介紹這一點(diǎn)。
事件在 Draft 內(nèi)部的傳遞
Draft
由事件驅(qū)動(dòng)饵沧,任何事件的觸發(fā)最終都會(huì)被轉(zhuǎn)化為一個(gè)新的EditorState
锨络。上圖是一個(gè)簡(jiǎn)單的流程圖,展現(xiàn)了事件在 Draft 內(nèi)部的傳遞機(jī)制狼牺。
react
只負(fù)責(zé)事件的綁定與view
的展示羡儿,將Draft
中內(nèi)置的事件editorBlur
等方法與原生事件blur
進(jìn)行綁定,下面給出了Draft
源碼進(jìn)行說明:
// DraftEditor.react.js
// 經(jīng)過精簡(jiǎn)
render() {
<div
// 將原生事件與Draft內(nèi)置事件相綁定
onBeforeInput={this._onBeforeInput}
onBlur={this._onBlur}
onCopy={this._onCopy}
onCut={this._onCut}
onDragEnd={this._onDragEnd}
onDragEnter={this.onDragEnter}
...
// 請(qǐng)暫時(shí)忽略下面這部分
<DraftEditorContents {...editorContentsProps} />
</div>
}
通過上面的代碼部分我們可以看到是钥,react將原生事件與內(nèi)置事件做了綁定掠归,例如將_onBlur
綁定到了原生事件onBlur
上面缅叠。而_onBlur內(nèi)部的事件則被單獨(dú)抽象出來,與視圖層完全解耦虏冻。
Draft
運(yùn)用了一些很酷的小技巧來解決內(nèi)置事件與原生事件的綁定問題:
// 經(jīng)過精簡(jiǎn)
import React, { Component } from 'react';
import {onBlur, onCopy, onFocus} from './logicLayer';
const handler = {
onBlur(e) {
editOnBlur(e);
}
onCopy(e) {
editOnCopy(e);
}
onFocus(e) {
editonFocus(e);
}
}
class DraftEditor extends Component {
constructor(props){
super(props);
// 事件綁定
this._onBlur = this._buildHandler('onBlur');
this._onCopy = this._buildHandler('onCopy');
this._onCut = this._buildHandler('onCut');
this._onInput = this._buildHandler('onInput');
...
}
_buildHandler(eventName) {
return e => {
const method = this._handler && this.handler[eventName];
method && method(this, e);
}
}
}
核心函數(shù)是_buildHandler
,通過此函數(shù)進(jìn)行事件綁定的分發(fā)肤粱。
通過這種方式,可以完成視圖層與邏輯層的解耦厨相。
任何事件的觸發(fā)最后都會(huì)被轉(zhuǎn)化為一個(gè)new EditorState
,通過onChange(update)方法拋出领曼,我們接收到new EditorState
后,再將其綁定到Draft
上面蛮穿,由Draft
負(fù)責(zé)EditorState
的轉(zhuǎn)換庶骄,最終通過react渲染出來。
也就是說践磅,任何new EditorState
都一定會(huì)被Draft
拋給我們单刁,再由我們綁定到Draft
上面進(jìn)行展示,EditorState
不是一個(gè)內(nèi)部狀態(tài)音诈。
當(dāng)然Draft
對(duì)EditorState進(jìn)行轉(zhuǎn)換的過程遠(yuǎn)遠(yuǎn)沒有這么簡(jiǎn)單幻碱,實(shí)際情況要復(fù)雜的多,這點(diǎn)我們將會(huì)在下面提到细溅。
通過上面所提到的這種方式褥傍,Draft
完成了由事件到狀態(tài)對(duì)象的轉(zhuǎn)化,并且完成了數(shù)據(jù)的單向流動(dòng)喇聊。
Draft 事件層和展示層的分離
我在上面大致畫出了draft
的react
層是如何劃分的恍风。其實(shí)這個(gè)圖并不準(zhǔn)確,但是用來說明已經(jīng)夠用了誓篱。
在react
層將事件綁定層與實(shí)踐展示層分離:
// DraftEditor.react.js
// 經(jīng)過精簡(jiǎn)
/**
* Event層
*/
render() {
<div
// 將原生事件與Draft內(nèi)置事件相綁定
onBeforeInput={this._onBeforeInput}
onBlur={this._onBlur}
...
/**
* View 層
*/
<DraftEditorContents {...editorContentsProps} />
</div>
}
仔細(xì)查看上面的代碼朋贬,依舊是相同的render
函數(shù),這次我將事件綁定的部分隱去了大部分窜骄,主要可以看到在這個(gè)組件中引入了DraftEditorContents
組件锦募,這個(gè)組件就是事件的展示層。在此層中邻遏,儲(chǔ)存了preEditorStatus
,View
層負(fù)責(zé)將diff
過后的latestEditorStatus
渲染出來糠亩。
中間會(huì)經(jīng)過一些過程,在此期間Draft
會(huì)向外暴露一些端口用于處理類似于block
樣式與inline
樣式准验,具體內(nèi)容會(huì)在擴(kuò)展中提及赎线。