作過前端的朋友,你們或多或少都接到過作用戶交互的需求。這時候只要一聽到產品經理說能不能支持加粗,斜體和@好友,你們確定就會在內心默唸「S**t,又要跳富文本編輯器的坑了」。javascript
曾經知乎上面有過一個問題,有多大比例的前端工程師,能在合理的時間內獨立開發出一個足以供商業網站使用的文本編輯器?你們一致認爲在千分之一,甚至萬分之一左右。這樣咱們要先了解富文本編輯器的各類特性(坑),才能往成爲千分之一的道路前進。css
富文本編輯器的坑在我總結起來有兩大類:html
一是視圖層的繪製,Facebook早期是使用<div>在<textarea>上面實現效果,而且須要大量使用了DOM測量。早期Facebook工程師發愁的事情之一就是說起的藍色背景與文字偏離。前端
二是各類編輯時候的各類小(天)坑。好比光標位置,輸入法,兼容性。。。 java
面對上面的各類坑,一個傳統的解決辦法是使用DOM的特性,contentEditable。不過說到這不少同窗要開始翻白眼了,雖然有不少不錯的實現(tinyMec,Quill),可是contentEditable仍是有名的難易控制,而且在不一樣版本實現不一樣。react
不過在React出現以後,事情有了起色。做爲一個視圖層庫,React可以很好的抽象原生DOM的操做,讓開發者可使用組件來定義不一樣的富文本格式。能夠說一次性的下降了富文本編輯器的開發難度。 程序員
在React.js Conf 2016上面,Facebook開源了Draft.js,做爲Facebook一衆文本編輯需求的產品上面的新選擇(狀態發佈,評論,Facebook Note,Messenger)。 bash
Draft.js除了與React緊密的整合以外,另一個很大的優點就是利用contentEditable這個DOM特性解決一衆編輯器小坑的同時,使用immutable的數據結構來表明編輯器的狀態,很好的分離了DOM和state。因此除了Facebook,不少公司也上手了Draft.js,好比知乎。 前端工程師
Draft.js給富文本編輯器提供了一個很簡單明瞭的解決辦法,就是React -> view,immutable.js -> model,而後Draft.js提供編輯器操做做爲controller。讓咱們來看下面一個例子: 數據結構
import React from 'react';
import ReactDOM from 'react-dom';
import {Editor, EditorState} from 'draft-js';
class MyEditor extends React.Component {
constructor(props) {
super(props);
this.state = {editorState: EditorState.createEmpty()};
this.onChange = (editorState) => this.setState({editorState});
}
render() {
return (
<Editor editorState={this.state.editorState} onChange={this.onChange} /> ); } } ReactDOM.render( <MyEditor />, document.getElementById('container') ); 複製代碼
editorState能夠理解爲編輯器在某一刻的一個快照(snapshot)。同時editorState也是一個由不可變(immutable)數據類型構成的對象。依據editorState,咱們能夠實現對編輯器內容的嚴格控制,而且知道如何render編輯器界面。
而富文本功能的實現,既能夠經過已有的html element(h1,h2,ul,ol)也能夠經過自定義的CSS。
.superFancyBlockquote {
color: #999;
font-family: 'Hoefler Text', Georgia, serif;
font-style: italic;
text-align: center;
}複製代碼
編輯器的操做則是很是的函數式化,以前我提到過,每一個editorState能夠看作編輯器的一個快照。這樣每一個操做(加粗,刪除等)輸入參數爲editorState,返回結果也是一個editorState,再由DOM去render。這樣狀態機的設計,既函數式化,又能夠保證將編輯器操做流水線化。好比切換code模塊的接口就是:
toggleCode: (editorState: EditorState) => EditorState
複製代碼
除了Draft.js,如今開源社區還有一個相似的很火的開源富文本編輯庫 - Slate。
Slate除了沿用不少Draft.js的先進的想法以外,更是在插件化,簡化API接口方面作出了本身的特點。如今Gitbook和語雀都使用了Slate做爲底層編輯器,並且前幾天在Hacker News上面出現之後更是star數目一躍到了12000+(迫近Draft.js)。Slate官方介紹本身的優點有:
以前在舊金山跟Slate創始人Ian面基的時候,他也分享過本身開發富文本編輯器遇到過得各類坑和各類思考,而且但願把Slate作成一個徹底插件化的編輯器框架。(p.s.,不過做爲我的開發者,Ian小哥的任性,好比對IME和協同的支持的抉擇過程,也很是有意思)。
Slate的代碼模塊化程度很是高,設計也力求插件化優先。小哥做爲Rhode Island School of Design畢業,設計師轉的程序員,對接口設計的追求可見一斑(沒事改API接口名稱的習慣就不吐槽了)。
若是你們感興趣,我也計劃陸續推出幾篇解讀這個框架源碼的文章。
------各單位注意,立刻要開始打廣告了:p------
在研究了這麼多富文本編輯器,WYSIWYG編輯器以後,我和個人好基友也開發了一款面向hacker的筆記應用 - Tea:
如今已經開始內測啦,對咱們感興趣的同窗能夠去咱們上一篇文章(juejin.im/post/5bffad…),裏面有咱們項目更詳細的介紹和內測版下載連接。