Draft.js的事件處理機(jī)制

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)部的傳遞

eventInDraft.png

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 事件層和展示層的分離

Event&View.png

我在上面大致畫出了draftreact層是如何劃分的恍风。其實(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ò)展中提及赎线。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市糊饱,隨后出現(xiàn)的幾起案子垂寥,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,695評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件滞项,死亡現(xiàn)場(chǎng)離奇詭異狭归,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)蓖扑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門唉铜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人律杠,你說我怎么就攤上這事【和铮” “怎么了柜去?”我有些...
    開封第一講書人閱讀 168,130評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)拆宛。 經(jīng)常有香客問我嗓奢,道長(zhǎng),這世上最難降的妖魔是什么浑厚? 我笑而不...
    開封第一講書人閱讀 59,648評(píng)論 1 297
  • 正文 為了忘掉前任股耽,我火速辦了婚禮,結(jié)果婚禮上钳幅,老公的妹妹穿的比我還像新娘物蝙。我一直安慰自己,他們只是感情好敢艰,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評(píng)論 6 397
  • 文/花漫 我一把揭開白布诬乞。 她就那樣靜靜地躺著,像睡著了一般钠导。 火紅的嫁衣襯著肌膚如雪震嫉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,268評(píng)論 1 309
  • 那天牡属,我揣著相機(jī)與錄音票堵,去河邊找鬼。 笑死逮栅,一個(gè)胖子當(dāng)著我的面吹牛悴势,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播证芭,決...
    沈念sama閱讀 40,835評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼瞳浦,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了废士?” 一聲冷哼從身側(cè)響起叫潦,我...
    開封第一講書人閱讀 39,740評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎官硝,沒想到半個(gè)月后矗蕊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體短蜕,經(jīng)...
    沈念sama閱讀 46,286評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評(píng)論 3 340
  • 正文 我和宋清朗相戀三年傻咖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了朋魔。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,505評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡卿操,死狀恐怖警检,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情害淤,我是刑警寧澤扇雕,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站窥摄,受9級(jí)特大地震影響镶奉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜崭放,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評(píng)論 3 333
  • 文/蒙蒙 一哨苛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧币砂,春花似錦建峭、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蜜徽,卻和暖如春祝懂,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背拘鞋。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工砚蓬, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人盆色。 一個(gè)月前我還...
    沈念sama閱讀 48,921評(píng)論 3 376
  • 正文 我出身青樓灰蛙,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親隔躲。 傳聞我的和親對(duì)象是個(gè)殘疾皇子摩梧,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,286評(píng)論 25 707
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)宣旱,斷路器仅父,智...
    卡卡羅2017閱讀 134,701評(píng)論 18 139
  • 學(xué)習(xí)如何在Flow中使用React 將Flow類型添加到React組件后,F(xiàn)low將靜態(tài)地確保你按照組件被設(shè)計(jì)的方...
    vincent_z閱讀 6,366評(píng)論 4 21
  • 提高Xcode編譯速度主要有一下三個(gè)方面 1. 提高Xcode編譯時(shí)使用的線程數(shù) defaults write c...
    天天想念閱讀 707評(píng)論 0 1
  • 魏慶軍我的快樂就是想你 拾一場(chǎng)兒時(shí)的安逸 和靜謐 筆墨追逐你 拼圖的思緒 歲月,消淺了彼此無言的美麗 青春的短笛 ...
    慶軍_a3d7閱讀 251評(píng)論 2 2