引言

富文本编辑器大概是最复杂、使用场景却极广的组件了。

可以说富文本编辑器让Web数据录入充满了无限的想象空间,如果只有文本框、下拉框这些纯文本的数据录入组件,那么Web的数据录入能力将极大地受限。我们将无法在网页上插入图片、视频这些富文本内容,更无法插入自定义的内容。

富文本编辑器让Web内容编辑变得更轻松、更高效,我们几乎可以在富文本编辑器中插入任何你想插入的内容,图片、视频、超链接、公式、代码块,都不在话下,甚至还可以插入表格、PPT、思维导图,甚至3D模型这种超复杂的自定义内容。

富文本编辑器的场景在Web上也是随处可见,写文章、写评论、意见反馈、录需求单,都需要使用到富文本。

今天的主角 Lexical,是 facebook 开源的一款富文本编辑器,我们来看它的介绍

Lexical is an extensible text editor framework that provides excellent reliability, accessibility and performance.

看起来好像很强,而且这个仓库的 star 数已有 8.7k,但是往下一看

⚠️ Lexical is currently in early development and APIs and packages are likely to change quite often.

确实,目前版本还只是 0.2.5,我查了查这个仓库最早的创建时间是 2020-12-03,热知识,其实 facebook 早在 2016-02-19 就开源一个一款富文本编辑器叫 draft-js,那为何又要再开源 Lexical 呢,让我们来一探究竟。

启动

我们先看看他的官网,直接有配合 react 的例子,果然不愧是 Facebook 出品的,话不多说 ctrl c v run 然后看下界面

虽然我知道现在很多流行的富文本编辑器都不是开箱即用的,但是我 ctrl c v 了好歹几十行代码,这出来的界面也太丰富了吧,跟 ProseMirror 可有丶像。

加点东西

那我们看看给它加点东西,先看看官网的 demo ,demo 里的功能很丰富,而且代码就在 Lexical 仓库里,那不如 ᶘ ͡°ᴥ͡°ᶅ

当我打开代码一看,什么,居然用的是 flow 而不是 ts,都这个年代了,真是成也 Facebook 败也 Facebook。不过不重要,这并不能阻拦我 copy 的决心,我准备先给编辑器加个插入图片的功能。

我们先分析一下我们想要的效果,需要一个 button,按下 button,插入一个 img 标签到富文本里,这其中需要一个类似菜单的 button,需要富文本支持 img 标签,还需要点击 button 后有个插入的操作。

如何让 Lexical 支持 img 标签呢,来看看官网怎么说

Nodes are a core concept in Lexical. Not only do they form the visual editor view, as part of the EditorState, but they also represent the underlying data model for what is stored in the editor at any given time.

看来我们先写一个 ImageNode ,ctrl c v,行了我们现在有了。

 import {DecoratorNode,
} from 'lexical';export class ImageNode extends DecoratorNode {__src;__altText;__width;__height;static getType() {return 'image';}static clone(node) {return new ImageNode(node.__src,node.__altText,node.__width,node.__height,);}constructor( src,altText,width,height,key, ) {super(key);this.__src = src;this.__altText = altText;this.__width = width || 'inherit';this.__height = height || 'inherit';}createDOM(config) {const span = document.createElement('span');const theme = config.theme;const className = theme.image;if (className !== undefined) {span.className = className;}return span;}updateDOM() {return false;}decorate() {return (<imgsrc={this.__src}alt={this.__altText}width={this.__width}height={this.__height}/>);}
}export function $createImageNode( src,altText,maxWidth, ){return new ImageNode(src, altText, maxWidth);
}

然后自己写一个 button,接下来应该要写插入的事件了,但是我发现了一个有意思的事,在 Lexical 中,这样的操作叫 Commands,需要自己创建,于是我们 ctrl c v,有了这么一个 ImagePlugin 组件。

import {useEffect} from 'react';
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
import {$getSelection,$isRangeSelection,$isRootNode,COMMAND_PRIORITY_EDITOR,createCommand,
} from 'lexical';import {$createImageNode, ImageNode} from '../nodes/ImageNode';export const INSERT_IMAGE_COMMAND =createCommand();export default function ImagesPlugin() {const [editor] = useLexicalComposerContext();useEffect(() => {if (!editor.hasNodes([ImageNode])) {throw new Error('ImagesPlugin: ImageNode not registered on editor');}return editor.registerCommand(INSERT_IMAGE_COMMAND,(payload) => {const selection = $getSelection();if ($isRangeSelection(selection)) {if ($isRootNode(selection.anchor.getNode())) {selection.insertParagraph();}const imageNode = $createImageNode(payload.src, payload.altText, 200);selection.insertNodes([imageNode]);}return true;},COMMAND_PRIORITY_EDITOR,);}, [editor]);return null;
}

可以看到,imagePlugin 里自定义了一个 Commands,里面携带的逻辑就使用刚才的 ImageNode 初始化一个实例然后插入编辑器,这里有一个小细节,这边使用的 editor是通过 useLexicalComposerContext 获取的,所以这个 ImagePlugin 组件必须要放在 LexicalComposer 组件内,其实包括刚才说的 button,也都会放在这里,LexicalComposer是富文本的核心。

button 的代码就随意写了

<button onClick={() => {editor.dispatchCommand(INSERT_IMAGE_COMMAND, {altText: 'Yellow flower in tilt shift lens',src: jay,});}}>insert image</button>

我们来看下效果

点击 button,插入图片(我的照片),完成。

搞点难度

我们回到我取的这个标题,为什么要扯上 Quill呢(当然不是因为我只用过 Quill 拉),因为 Quill 是目前开源的富文本编辑器里面 star 数最高,而且模块化支持的也比较友好,不过 Quill 比较难以接受的缺点就是对嵌套结构的 DOM 不够友好,例如在 table 标签里面 加 ul li 标签,这样的解构 Quill 需要自己开发相关的插件来支持,成本不小,那么我们看看 Lexical 如何呢。

又是一通 ctrl c v,看下效果

虽然看起来有些小问题,但是对嵌套结构是比较友好的。

总结

前面都只是一些尝试,我不太想做官网的搬运工,我来直接说一下我对 Lexical 的理解。

Lexical 本身是比较切合 React 的,这个是天生自带的优势

每一个 DOM 类型,都需要有 对应的 node,当然 Lexical 会有内置一些比较基础的 node,table、list、link 等。

每一个操作 Commands,也需要自己注册,当然也会内置一些 Commands,KEY_ENTER_COMMAND、CLICK_COMMAND 等。

刚才我们插入图片的逻辑是怎么完成的呢,先写好一个 ImageNode 描述 img 标签,初始化的时候带上,再写好一个 ImagePlugin,注册这个插入图片的操作,然后在 button 的点击事件里触发这个操作。

Lexical 自身的数据结构使用它自定义的 state 来描述,里面的核心有两个,一个是 node 树,一个是 selection,node 树我们可以理解,一个 DOM 对应一个 node,那么 DOM 树当然对应 node 树,顺带提一句,树型结构也利于做嵌套处理,selection 就是表示选区了,在富文本里也是一个常见概念,表示鼠标选取中的区域。

但是我们平常怎么使用呢,比如富文本一通操作后得出一个 state,我们总不能把这个 state 提交给后端接口吧,Lexical 当然有给我们提供了方法。

Editor states are serializable to JSON, and the editor instance provides a useful method to deserialize stringified editor states.

const stringifiedEditorState = JSON.stringify(editor.getEditorState().toJSON());const newEditorState = editor.parseEditorState(stringifiedEditorState);

意思是,把 Lexical 自定义的数据结构 state 序列化成 JSON 字符串,传给后端,初始化的时候,把这个 JSON 字符串反序列化成 state。

说实在的,我并不是很喜欢这种方法,这意味着,和当前的富文本编辑器强绑定,如果万一后期我想换另一个富文本编辑器,无法实现,因为其他富文本编辑器怎么会支持这套 state。

当然 Lexical 自己也有说

With Lexical, the source of truth is not the DOM, but rather an underlying state model that Lexical maintains and associates with an editor instance.

意味着我们就不能直接用 html 字符串和 Lexical 进行交互了,我觉得是8太行的,当然,也有黑科技可以实现,比如我们粘贴复制一段富文本到 Lexical 也是会生成相应的 state 的,那么你就可以参照 lexical-clipboard 的处理逻辑写一个 htmlToState ?,这么麻烦,淦,还玩个

Facebook 新品 Lexical, 比 Quill 更好用的 Editor ?相关推荐

  1. Google VS Facebook,哪个能带来更好的效果?

    众所周知,Facebook 和 Google 是目前最受欢迎的两个广告平台.这两个平台都拥有数十亿用户和海量数据集,可帮助公司将广告展示在意向客户面前. 作为搜索引擎的 Google 和社交媒体平台的 ...

  2. 百度世界发布渡鸦新品,软硬件结合更懂生活

    百度世界发布划时代产品,软硬件结合更懂智能生活 11 月 16 日,2017 百度世界大会在北京盛大举行.百度在会上发布了手机百度 10.0 和全新人工智能硬件"Raven H"等 ...

  3. Facebook的智能音箱跳,票,了

    安妮 编译自 Bloomberg 量子位 出品 | 公众号 QbitAI Facebook的智能音箱要跳票了. 据外媒报道,知情人士透露,Facebook将取消在5月份举办的开发者大会上发布智能家居新 ...

  4. 2018谷歌I/O开发者大会8大看点汇总 新品有哪些

    2018谷歌I/O开发者大会8大看点汇总 新品有哪些美国科技媒体The Verge近日撰文,列举了在即将召开的2018年谷歌I/O开发者大会上的8大看点,包括Android P.人工智能等等. 以下为 ...

  5. Facebook如何运用机器学习进行亿级用户数据处理

    编译 | AI科技大本营(rgznai100) 参与 | 刘畅.尚岩奇.林椿眄 审校 | reason_W 2017年末,Facebook应用机器学习组发布最新论文,对整个Facebook的机器学习软 ...

  6. 突发 | Yann LeCun卸任!Facebook变天,做AI不能落地是不成了

    作者 | 波波 编辑 | 谷磊 1月24日早间重磅消息,Facebook 人工智能研究部门(FAIR)的负责人Yann LeCun 宣布卸任,之后将担任Facebook首席人工智能科学家,保留对FAI ...

  7. 跟风Google Brain,Facebook AI研究机构启动见习项目

    2015年,Google Brain公布了其帮助机器学习研究者进阶的见习项目,研究内容灵活.薪资福利又高.发展机会应有尽有,瞬间吸引了大量的申请者,其中甚至还有Node.js之父Ryan Dahl,A ...

  8. CMU 刘畅流:爱上人机交互源于科幻片,女性研究AI更感性、更哲学 | 妇女节特辑...

    她力量 近年来,"她"力量正在科学家群体中快速升温. 在一年一度的妇女节到来之际,智源社区选取了五位颇具代表性的女性科学家,进行了深度访谈.在她们中,有人选择食物图像识别,对选择的 ...

  9. 兰艳艳:理想温暖10年科研路,女性可以柔和,更要自信、专业 | 妇女节特辑...

    她力量 近年来,"她"力量正在科学家群体中快速升温. 在一年一度的妇女节到来之际,智源社区选取了五位颇具代表性的女性科学家,进行了深度访谈.在她们中,有人选择食物图像识别,对选择的 ...

最新文章

  1. Cocos-2d 坐标系
  2. 读文件 —— WEB前端读取本地文件内容哪些事(前台解析txt文件)……
  3. C++中数组访问操作符的重载
  4. [leedcode 52] N-Queens II
  5. 轴固定位置_轴承的装配与内外圈固定方法,一文让你搞懂
  6. php中引入jquery文件_WP模板开发中,怎样给wordpress网站的文章,添加点赞功能?...
  7. 《移动浪潮》读书笔记
  8. wps linux 字体目录在哪个文件夹,WPS OFFICE怎么添加字体?(我下载的字体文件应当放那个文件夹?)...
  9. 三菱触摸屏程序和三菱PLC程序,程序都有注释
  10. python画图-python绘图入门(完整版)
  11. int类型和String类型相互转换
  12. 【智能制造】简单明了让你了解什么是柔性制造
  13. openharmony开发TS语言基础
  14. SQLiteSpy介绍和使用
  15. Vue2.0 —— 由设计模式切入,实现响应式原理
  16. 通过爬虫获取银行名称
  17. python批量修改及创建txt
  18. 逍遥模拟器使用指南(四、逍遥安卓模拟器电脑版xposed框架教程)
  19. 简单的键盘按键记录(无码)/虚拟地址转物理地址/生成随机字符串/计算字符串哈希
  20. LibGDX QQ群建立,欢迎对libGDX有兴趣的程序员加入。

热门文章

  1. linux的create命令,createuser命令
  2. paddle第十九期3天训练营3.14-day2
  3. 勒索病毒之后 企业文件安全保护如何落到实处?
  4. 计算机屏幕尺寸不是全屏,为什么把电脑显示器分辨率调成1366X768后网页不能全屏显示呢?...
  5. 司法制度类毕业论文文献包含哪些?
  6. java图书馆_java编写图书馆管理系统
  7. 图书馆借阅代码Java_java图书馆管理系统源代码 图书借阅和归还管理
  8. 电信卡_短信查询指令
  9. 【MariaDB】安装MariaDB,与MySQL并存
  10. android电视怎么打开网页,智能电视怎么浏览网页?这三款浏览器完美解决!