9.6K Star!可擴(kuò)展的富文本編輯框架!
簡介
Lexical 是一個可擴(kuò)展的 JavaScript 網(wǎng)頁文本編輯器框架,強(qiáng)調(diào)可靠性、可訪問性和高性能,旨在提供一流的開發(fā)人員體驗,輕松地制作原型并充滿信心的構(gòu)建功能。結(jié)合高度可擴(kuò)展的架構(gòu),Lexical 允許開發(fā)人員創(chuàng)建在大小和功能上可擴(kuò)展的獨特文本編輯體驗。
Lexical 可以輕松創(chuàng)建復(fù)雜的文本編輯體驗,否則使用內(nèi)置瀏覽器工具會非常復(fù)雜,比如可以用來構(gòu)建這些:
- 比 a 標(biāo)簽有更多要求的簡單純文本編輯器 textarea,例如定義表情符號、鏈接、主題標(biāo)簽等功能
- 更復(fù)雜的富文本編輯器,可用于在博客、社交媒體、消息傳遞應(yīng)用程序上發(fā)布內(nèi)容
- 一個成熟的 WYSIWYG 編輯器,可用于 CMS 或富文本編輯器
- 結(jié)合上述特點的實時協(xié)作文本編輯
Lexical 具有以下特點:
- 可靠性。Lexical 由每個附加到單個內(nèi)容可編輯元素的編輯器實例組成,一組編輯器狀態(tài)代表編輯器在任何給定時間的當(dāng)前和待定狀態(tài)。
- 可訪問性。Lexical 遵循 WCAG 中建立的最佳實踐,并與屏幕閱讀器和其他輔助技術(shù)兼容
- 效率高。它不直接關(guān)注 UI 組件、工具欄或富文本功能和 markdown,這些功能的邏輯可言通過插件接口包含在內(nèi)
支持以下瀏覽器:
- Firefox 52+
- Chrome 49+
- Edge 79+
- Safari 11+
- iOS 11+ (Safari)
- iPad OS 13+ (Safari)
- Android Chrome 72+
項目地址:
https://github.com/facebook/lexical
幾個重要的概念
編輯器實例
編輯器實例是將所有東西連接在一起的核心,可以將 contenteditable DOM 元素附加到編輯器實例上,注冊和監(jiān)聽命令,更重要的是,編輯器允許更新其自身的 EditorState。
// 創(chuàng)建編輯器實例
createEditor()
編輯器狀態(tài)
編輯器狀態(tài)表示你希望在 DOM 上顯示的內(nèi)容的底層數(shù)據(jù)模型,包含兩部分:
- Lexical 節(jié)點樹
- Lexical 選定器對象。編輯器狀態(tài)一旦創(chuàng)建就不可更改,可以使用以下方法進(jìn)行創(chuàng)建:
editor.update(() => { })
可以將節(jié)點轉(zhuǎn)換或命令處理程序作為鉤子掛到 update 方法中,它們將作為更新流程的一部分而被調(diào)用,以防止更新的級聯(lián)/瀑布式更新。
// 獲取當(dāng)前編輯器狀態(tài)
editor.getEditorState()
// 編輯器狀態(tài)可以被序列化成 JSON,通過該方法將 JSON 轉(zhuǎn)換回實例對象
editor.parseEditorState()
編輯器更新
如果想要更改編輯器狀態(tài)中的某些內(nèi)容,必須通過更新操作來完成:
editor.update(() => { })
傳遞給更新調(diào)用的閉包很重要,這是一個擁有活動中編輯器狀態(tài)完整上下文的地方,它公開了對底層編輯器狀態(tài)節(jié)點樹的訪問。
DOM 協(xié)調(diào)器
Lexical 有自己的 DOM 協(xié)調(diào)器,它采用一組編輯器狀態(tài)(總是“當(dāng)前”和“待定”)并在它們上應(yīng)用“差異”。然后它使用此差異僅更新 DOM 中需要更改的部分,可以將其視為一種虛擬 DOM,使得 Lexical 能夠跳過許多差異比較工作,因為它知道在給定更新中發(fā)生了哪些變化。
監(jiān)聽器、節(jié)點轉(zhuǎn)換和命令
除了調(diào)用更新之外,使用 Lexical 完成的大部分工作是通過監(jiān)聽器、節(jié)點轉(zhuǎn)換和命令完成的。這些操作都來自編輯器實例,以 register 開頭。另一個重要特性是所有注冊方法都返回一個函數(shù)以輕松取消訂閱它們。
const unregisterListener = editor.registerUpdateListener(({editorState}) => {
console.log(editorState);
});
unregisterListener();
命令是用于將 Lexical 中的所有內(nèi)容鏈接到一起的通信系統(tǒng),當(dāng)按鍵被觸發(fā)或其他重要信號出現(xiàn)時,語法在內(nèi)部調(diào)度命令,傳入的命令按優(yōu)先級通過所有處理程序進(jìn)行傳播,類似于瀏覽器的時間傳播機(jī)制
// 創(chuàng)建自定義命令
createCommand()
// 發(fā)送到編輯器實例
editor.dispatchCommand(command, payload)
// 也可以直接注冊命令
editor.registerCommand(handler, priority)
一個簡單的例子
這個例子可以用來創(chuàng)建一個簡單的富文本編輯器:
import "./styles.css";
import Editor from "./Editor";
export default function App() {
return (
<div className="App">
<h1>Rich Text Example</h1>
<p>Note: this is an experimental build of Lexical</p>
<Editor />
<div className="other">
<h2>Other Examples</h2>
<ul>
<li>
<a
href="https://codesandbox.io/s/lexical-plain-text-example-g932e"
target="_blank"
rel="noreferrer"
>
Plain text example
</a>
</li>
</ul>
</div>
</div>
);
}