与WangEditor作者的交流会

1,327 阅读15分钟

作者:BEF团队+王福朋

上周,我们很荣幸的请来了wangEditor的作者王福朋。跟我们共同讨论在开发编辑器的过程中,遇到的问题和心得。也为我们最近的一些研究,答疑解惑。下面就是交流会上所有问题的整理。

问题1

slate方面, 目前有没有识别docx的转换器/插件

福朋:在V4版本已经关闭的issue里,关于粘贴的问题是最多的。目前没有发现可以识别word、或者直接从网页复制的第三方,因为很难保证粘贴完之后的文档效果。

所以我建议是这样的,把你们特别需要做的场景,枚举出来,然后剩下的东西,直接不管了,或者慢慢的再做。你们想随便找个doc或者网页粘贴过来,这不可能。Word的粘贴,你也得找场景,比如说一个标题,一个文字,还是说一个图片,还是说一个word里面一个表格,或者一个图又插了一个图,这些需求都得细化。所以这种需求,应该是用例先行,测试驱动开发的这种方式来做是比较靠谱的。你如果先写代码,估计写着写着就乱了。测试驱动开发,单独做一个模块,然后要写单测。因为你随便改一点,可能就会乱套。把粘贴、转换的模块、函数,拿出来用单测跑,是非常好的。

所以这个问题的结论是:1、粘贴不能满足所有的需要。2、测试先行,用例先行,场景先行。

问题2

slate编辑器有没有懒渲染功能, 当json节点非常多时(比如贴了本红楼梦), 页面是否会出现性能问题, 目前是否有解决方案?

福朋:我这有个demo可以看下,现在我最新版本的编辑器,有一个大文件,它是10万字的。10万左右还好,但是要做其他的操作,比如说全选,比如说撤销,全选之后再撤销,就会有一些卡顿,也就是大批量文字处理,就会卡顿。这个问题,应该担心的就是渲染这部分能力。因为本身是slate内核,它本身是不包括渲染的。我自己写的渲染方案,肯定是没有react来的好。

几万字,几万字,甚至到了十几万字的级别都是没有问题的。这是我的感觉,但也不能保证,因为操作也是不可枚举的,普通的输入操作和直接大批量选中之后的操作,那肯定是不一样的。

问题3

wangEditorV5版本中, paragraph节点支持哪些属性? 看d.ts文件只支持type/children属性, 但实际测试时发现支持textAlign/lineHeight等属性, 搜索源代码没有找到实现的地方, 这是怎么做到的?

源码中对paragraph的定义

export type ParagraphElement = {
type: 'paragraph'
children: Text[]
}

福朋:这是个细节问题。paragraph节点的,文本对齐,还有行高,他是个单独的。因为他这个文本的行高,它不仅仅适用于paragraph,也可能会用标题,也可能会用于表格的单元格儿。所以就是你不能把它定义到paragraph里面,如果定义到paragraph里面的话,其他的element也得重新定义一遍,所以就单独定义出来了。源码在这里。你可以看到,源码里有basic models,还有好多model,models里面其实就有line-height。这个custom type自己定义。只要是element就可以有line-height的属性。line-height的操作全是在line-height的model里面去操作的,他不会在paragraph里面操作,所以说我们在paragraph这里面定义的时候,不用定义这个line-height,因为JS语法本身是一个语法的限制,而不是运行时的限制。所以说,只要paragraph这个里面我们没有操作line-height,我们就可以不写。但是我们在运行时的时候,我们就可以去往里面塞各种各样属性,因为运行时他不会去限制你的。像标题、引用、表格……,都可以扩展line-height属性。所有的模块,都是在custom types.ts这里定义的。像文本对齐是在上一层justify那个目录里。最后所有的custom types都汇集到package下面。package目录下面,有个custom types.d.ts。可以看到所有的定义。

问题4

slate中能否支持插入antd的input组件, 并支持antd里的接口?

福朋:支持。API肯定支持,都是JS的代码,为什么不支持他的API呢。只是有一个小坑儿,就是你如果在编辑器里面去去渲染input或者textarea这种输入框的组件,需要严格的考虑或者验证focus。比如说你的鼠标点击了文字,这时focus到这个编辑器上了,但是你的鼠标点击里面的input,那此时编辑器是聚焦了,还是失焦了?这个得需要你自己去定义。这里给大家放一个例子,就是一个视频+一个输入框

问题5

相较于大厂出的draftjs等类似竞品, slate编辑器稳定吗, 可以满足类word编辑器的需求吗?(背景: slate编辑器总代码不到1w行)

福朋:稳定应该是没有问题的。slate分成三个包,一个是核心包。二是稳定包,三是工厂包。比较核心的包,一是定义了内核,wangEditor用的就是slate的内核。二是react的视图层。所以说。它的稳定性是没有问题的,而且它功能比较少,视图层没有实现太多功能。基本能满足word类的需求。但你们自己需要在视图层做大量的定义,需要在视图层写大量的扩展功能,比如说图文混排,比如类似于块编辑器的能力。

slate从2018年开始做的,中间又升级过一版,0.50版本是更加人性化、更加好一些的,我们看过slate的测试用例,测试用例也是写的比较全的。就整体来说,稳定性还是没有问题的。当然,它能保证最基本的功能和扩展性。但没法保证他什么都有。他的优势就是,slate是后起之秀,结合了之前的比较好的优点。然后他的数据模型也比较清晰,源码也不多。源码少是个好事情,源码少了,很方便在上面继续扩展,可控性好。实在有啥问题,你们改改源码就行了,比较精简。它不像prose mirror那么庞大,用起来成本比较高。我当时之所以选slate做内核,也是因为他是比较经典的内核,至今也没有发现他有什么bug。

问题6

开发过程中,有没有遇到特别大的坑?

福朋:印象比较深的是拼音。因为老外没有拼音,输入字母数字都没有问题,可一旦输入拼音,问题全来了。比如拼音和选区的冲突,比如全选之后输入拼音,比如全选之后删除再输入拼音等等这些场景,反正我们拼音那块儿的代码,也是写的挺乱的。可以把源码发给你们看一下。 我曾经做过一个功能,就是max length最大长度的问题。就因为拼音卡了很久。输入数字字母的话,这个max length很好判断。但你一旦输入拼音,就不好判断了。而且截取之后,还有可能把汉字也给截断了。

除了拼音的坑,还有一个大坑,就是最近大家用wangEditorV5最新版本,反馈比较多的,比如:我们创建编辑器,然后编辑写内容,写完内容保存,它肯定是个Json的结构。我们再次编译的话,要回传这个json的结构,显示到编辑器中,然后再次编辑。但是我之前版本的用户呢,他们存的都是HTML结构的,就是之前版本都是HTML结构编辑的,所以说,他们就是说能不能把我的html结构传递到你的新版编辑器中去编辑,我就一直没有敢答应他们去弄,现在也不支持。

很多编辑器,它给用户的这个这个印象是什么?他的demo上是允许你输入html做初始化内容的。但是你想一下,完全的100%的html,肯定是不可能的。就举加粗这个例子,用html和css实现加粗,至少能有5种写法。100%回显到编辑器,肯定是不可能的。如果需求一定一定要插入html,那我后面可以考虑提供一个危险性插入的接口。就是让用户可以插入一些大概的标签,但是不保证所有的标签都能识别。反正这块儿,无论是用slate,还是draftJS,应该都是一样的,就是要坚守一个底线,就是我的存储数据必须是json数据。但是再想想,如果数据存储都是用json格式,那渲染的时候该怎么办?对,渲染的时候,浏览器是不识别json的,如果把json转成html来渲染的话,你想想,那html什么时候渲染呢?是不是把存储的json从服务端下载下来之后在前端渲染?这样的话就会很麻烦。为什么很麻烦?因为第一个渲染需要时间,第二个渲染还是要基于这套编辑器的,那么编辑器的体积就会非常大。现在wangEditer打包压缩完了都要几百KB。所以说,如果前端渲染,成本还是比较高的。如果服务端渲染的话,想把json变成html,那至少需要node做技术栈,如果用Java,还得去开发这套转换逻辑。而且随着转换逻辑的扩展,不同的类型的组件儿会越来越多。还有一种方式是什么呢?在编辑器编辑的时候,保存时就直接存两套数据,一套是json,一套是html。但这样的话就有一个问题,数据冗余了。我现在的这个V5版本的文章里面写过这个事情,跟我说的是一样的,大家可以去看一看。

还有一种场景,大家需要提前考虑好,就是我编辑了一个文档,然后直接发布或者分享出去。我分享的内容是纯文本的,没有编辑功能。那你还需要加载编辑器吗?

问题7

wangeditor-v5 基于slate,重点做了哪些优化?

算不上优化吧。我的内核基于slate,但视图层是我自己写的,所以支持react、vue、还有jquery。用MVC模式来看一下架构图(见下图)。另外我的掘金上也有一些总结

问题8

wangeditor-v5 在线协同,有成熟的方案吗?

福朋:在线协同我还没有做。明年可能会去尝试一下。现在市面上有一些技术方案是可以实现的。也有一些推荐Prose mirror的人,说它有比较好的解决方案。而slate的方案只是demo级别的。但从slate原子级的opration来说,理论上没有问题。

如果你们有协同编辑需求的人,从一开始做,每次设计就要考虑周全这个问题。比如说做表格,不能A随便一改,把B的表格全部覆盖了。或者随便一改,就把这个号删除了。尽量的改属性,而不是删属性。明年我打算做单元格合并,我就在想,是先做单元格合并,还是先把协同编辑的demo跑起来,然后再连带一个合并功能,因为实现了协同,可能会发现前面做的单元格合并不行,还要再推翻重做,就麻烦了。普通的修改颜色、输入文字,都问题不大。一旦有表单、单元格,这些复杂的内容,再掺杂了协同编辑,就是很有风险的。

问题9

wangEditor 的 render 层是自己实现的,你建议我们在你的编辑器上面,再封装一下好呢?还是自己写视图层更好呢?

福朋:如果你们有人力去自研、并且需求比较复杂的话,就不再建议用wangEditor来扩展了。因为你们不是做一个小型编辑器,你们想做的东西,需求比较多,如果用我的编辑器接的话,有可能做的四不像。之前有一个slate的插件集合,你们看一下。他把一些比较基础的功能,像链接、列表、表格、paragraph、板块儿什么的,都实现了。如果你们有定制需求,就基于slate自己开发就好了。

问题10

为什么diff这块,选择了vue的diff算法?

福朋:因为我只研究过snabbdom,对这个比较熟,它受众比较多,也接受了VUE2的验证了。snabbdom是第三方独立的,怎么用都行。

问题11

wangEditor 对于表单的支持情况,有没有什么经验?市面上有没有现成的组件库?

福朋:你们的需求,听上去特别像块编译器notion。这是现在最火的一个块编辑器的知识库。它理念就是,你可以自定义块儿,块儿可以认为是一个组件;一个富文本内容;一个表单内容。然后块和块之间可以随意拖拽,随意排版,比如说左边占2/3,右边1/3。

问:我们的需求,几乎都是自定义表单,就是说,用户可以自己定义表达的组件、格式和内容。所以基于成本,想考虑直接使用市面上的组件。

福朋:组件库倒好说,你这问题是在自定义表单,那怎么和编辑器集成起来,这才是难点。我的建议是,如果一开始需求不明确的话,可以先用传统编辑器的方式,插入表单类型去做。就是排版自由一些,让用户自己做,想回车就回车,想一行就一行。如果后面需求明确了,有了固定的表单组件或者模板,你们可以考虑做网页编辑器。像我之前做过,生成一些投票、游戏那种类似的。

问题12

在做html转slate的json, 遇到一个问题,html里有span标签,span节点本身没有结构属性,他的属性都是针对span内部的text设置的, 但是为了保存样式, 必须要建一个paragraph块。但这样会导致文本换行,我们有没有非paragraph块的代码结构, 还是必须要手工实现一个新的, 不会换行的type块定义?

福朋:按理说应该会转成text的节点,为什么要转成paragraph块儿呢?

答:因为span里面可能还套着span,html可能是乱写的。

福朋:那就回到第一个问题了,当然我的想法比较通用,简单粗暴一些,就是我把能识别的标签,通过属性分析出来,然后该怎么办怎么办,我识别不了的标签,就全部按照纯文本处理。

像你举的span标签这个例子,可以去定一个标准,就是你们的编辑器里面产出什么样的结构,就按照这个标准来做最基本的处理。比如你们的编辑器里面产出的html应该是什么样的结构,你就按照这个结构去反转处理。除此之外的结构你就可以不去外理。400个标签,只能做到尽量满足语义。思路应该是分成两层的,先做一层兜底的,再做一层是锦上添花的。

问题13

做了这个项目后,有没有可以分享的设计模式方面,包括架构方面的,心得

福朋:可以去看我的掘金。很多心得都写在上面了。

然后,再给大家看一个核心的接口,最后一个接口就是所有模块的定义。我现在,就是有四部分。第一部分,是菜单注册。就是我编辑器顶部栏的菜单。第二部分,是渲染model,就是把Json渲染成编辑区里面的虚拟DOM。第三部分是to html,我编辑是可以获取json的,而且还可以获取html。第四部分的slate的插件注册。大概我下个月要做一个扩展,就是通过HTML把源码转成Json。

最后一个问题

未来的长期规划?

福朋:我也曾考虑过商业化的想法,但这得一步一步探索。1是国内的现状。2是我的精力也有限。需求很多,就慢慢做吧。我希望近一、两年,做成一个开源的、免费的、不错的编辑器,大家用的舒服、顺手,就这个目标吧。