slate原始碼解析(一)- 序言

愛喝可樂的咖啡發表於2023-02-23

筆者從大學時期就開始接觸的前端,在剛去實習的時候就被導師安排去做內網的一個小富文字工具。之後從畢業後乾的第一份工作遊戲客戶端,到現在做著視覺化相關的前端工作,都有在做富文字相關的內容。可以說是和富文字編輯器(Rich Text Editor)有著不解之緣。

WYSIWYG

如無特別指出,該系列文章中所說的富文字都是指WYSIWYG模式的編輯器。WYSIWYG是英文"What You See Is What You Get"的縮寫,翻譯過來就是“所見即所得”。

這類產品中最久負盛名的就是Microsoft Word文件。Word文件提供了諸如字型、顏色、背景色、段落等針對文字樣式的支援外,還有各種頁面排版以及圖片、影片插入等富文字功能。並且也完全滿足WYSIWYG的原則(除了跨版本開啟Word文件時那令人惱火的排版錯亂問題)。

在Web端更是富文字應用大放異彩的地方。剛提到的Word文件很早之前就有了Web版本,除此之外還有大名鼎鼎Google Docs、前些年很火的筆記工具Notion等。國內近些年也興起了眾多類似模式的Web應用,如主打辦公協作的騰訊文件、飛書文件,偏向於知識庫管理的語雀等。

不同時代的富文字編輯器

回到開發者的視角;富文字應用可以說是前端中的“天坑”領域了。如果想最快的實現一個簡易的富文字,那麼只需在給DOM節點增加一個contenteditable=true即可讓頁面變為可編輯的模式。此外還有配套的API-execCommand可實現在編輯區域內撤銷、回退、變更文字樣式等功能。這麼看來,既然有瀏覽器的這些支援,那麼在Web端實現富文字應該並不是一件很難的事。 但坑就坑在了瀏覽器的相容性上。各個瀏覽器廠商對於execCommand支援程度是不同的,為了遮蔽各瀏覽器的差異而提供一套統一的API給開發者使用,就必須額外地做許多工作。曾經非常著名的CKEditor就是基於該方式實現的。

對於開源界中數量眾多的富文字庫,個人鐘意將其分為兩大類:

  • 舊時代的富文字編輯器:代表作CKEditor、TinyMCE、國內百度的UEditor以及眾多基於JQuery使用的富文字外掛。這些富文字編輯器的最大特點就是“開箱即用”。它們往往都沒有太多內建的概念,如果你並沒有深入應用的場景,那麼遵循官方文件能以非常簡單的方式引入便可以在頁面中擁有一個可用的富文字編輯器了。並且它們都有預置的極其豐富的各式功能,一般都是在初始化編輯器時以配置的方式傳入,以TinyMEC入門文件中的一段程式碼為例:

    只需在建構函式中傳入容器DOM的id和你需要的富文字工具欄的功能集陣列,就可以展示出一個完備的富文字編輯器出來了。
    而該型別編輯器的缺點非常明顯:(1) 能夠支援的功能侷限在庫本身所提供的功能集,可自定義的程度很低。(2) 沒有做Data Model和View的拆分,對於編輯器內容的儲存和匯出往往是與HTML標籤高度耦合的。雖然這種方式非常便於直接展示富文字內容,但如果想對儲存內容做遍歷分析或回顯調整等操作的話則會存在諸多不便的地方。並且儲存內容中包括太多的HTML標籤和樣式資訊會大大增加資料的體積。

  • 現代化的富文字編輯器:本系列文章的主角 - Slate.js以及同樣是基於React生態的Draft.js都可以稱為現代化的富文字編輯器。
    但這兩者其實更應該叫做富文字編輯器框架。與上一代的富文字編輯器不同,Draft.js和Slate.js不提供任何“開箱即用”的功能。它們都實現了將Data Model和View層的拆分。在View這一層,兩者都是基於React來做內容的自定義渲染。在Data Model層則是有一套框架自己定義的schema格式,在開發過程中主要精力就是關注在這套Data Model上以及從它們到View層的轉換。
    作為框架,它們沒有任何現成可用的富文字功能,僅是提供一系列開發編輯器所需的基礎“元件”和最基本的一套操作API。這就導致了相對於上代編輯器有了更高的上手門檻:哪怕是開發一個再簡陋的富文字應用,都需要從零開始實現,因此也有著更大的心智負擔和更多的程式碼量。

接下來

既然本系列文章是解析Slate.js的原始碼,先來看看Slate這個庫中有哪些包:

我們開發者最需要的是兩個包:

  • slate 資料模型層。Slate最核心的部分,完全使用Typescript編寫,包括了Slate資料模型的定義以及用於運算元據的對外介面。資料模型中的許多型別都是可擴充的(extendable),在後續講解自定義型別的時候還會細說。
  • slate-react檢視層。負責和前端框架React的對接,渲染富文字內容及使用者互動的處理。正是由於這種良好的架構,使得開發者除了可以選擇直接使用官方的slate-react作為檢視層,還可以在不同的前端框架下實現自己的檢視層,slate-angular就是一個非常優秀的例子。

至於slate-history包,則是用於為編輯器提供撤銷回退操作(undo/redo)的外掛,不過筆者還並不打算開slate-history的坑: ) 該系列文章中主要是專注於slateslate-react的原始碼解析。

筆者從0.62版本開始就開始調研Slate,當時可謂是一把辛酸淚: ( 各種花式Bug和瀏覽器相關的相容問題數不勝數;並且出了問題後能搜尋到的資料極少,慢慢翻Slate的issue板塊也不一定能有解決方案,往往最後之只能用非常hack的方式繞過去。 而在該系列文章,筆者打算基於0.82版本的原始碼作解析。0.82距最新版本很近,這也是筆者正在使用,已經引入生產環境中並穩定執行了的,曾經已知的許多bug和問題都已經得到了解決: )。

小結

本篇並沒有什麼實際的乾貨,筆者只是從自己的角度概述了下在Web端上富文字的分代和它們中典型開源庫的介紹,另外再提了下Slate下各個包的作用。但不著急,在下一篇我們就會真正進入到原始碼之中了:)

相關文章