公司组织的活动,发篇博文。前段时间正好项目需要富文本编辑器。同事用的draft.js,用起来麻烦。谷歌了下有啥别的解决方案,发现了slate.js,正好语雀底层也是用的slate.js定制的,就倒腾了起来。
slate.js 和 Draft.js, Prosemirror and Quill一样,都是基于结构化对象,渲染富文本编辑内容。简单的说,富文本编辑器的value不再是html,而是State Object.
e文不大好的同学可以看看中文的文档, github.com/loveloki/sl…
本来还想复制黏贴翻译一波官网的,有中文的大家就自己看下学习下吧。
看完walkthroughs,真的感觉既简单又实用,代码还是react hook,大厂还在用,就这个了买它买它~~当然还是很耐心的看完了Concepts,API
API章节没有中文翻译,大家可以锻炼下自己,看着这么详细的API,那不是更该支持一波
Transforms 转换是操作文档的辅助函数(Node 结点,Selection 选择区,Text 文本)
Nodes Editor的几个方法比较常用,代码中需要通过函数重写的方式进行扩展
Locations 位置相关的api
Refs 没看懂
Miscellaneous createEditor()
GitHub上搜了一波,看见了这个项目github.com/Canner/cann…,但是这个项目都是2年前的了(难道是我闭门太9了,以前都没听过slate.js)
看着官网的例子,感觉写个简单的应该不难,正好想认真学习下,也方便定制编辑器。写了个简单的实例,github.com/legu2009/sl…,公司组件库用的Braft Editor,所以UI借鉴了下(大家都懂的),实在是icon折腾了大半天,没有找到开箱即用的。组件用react hook写的。
总结下踩的小坑
event.preventDefault()
处理marks = Editor.marks(editor)
获取当前的状态判断。对于Element,通过 Editor.nodes(editor, { match: (n) => n.type === 'xxx' })
迭代进行查找Transforms.select(editor, tmpSelection.current);
恢复Selection, 在DropDown关闭的时候也进行恢复,并HTMLElement.focus() const onDropDownHide = () => { Transforms.select(editor, tmpSelection.current); if (isNewLink.current) { unwrapLink(editor); isNewLink.current = false; } getContainerNode().querySelector('.slate-content').focus();}; //行级别元素和文本才能处在一个children中,所以需要重写isInline editor.isInline = (element) => { return element.type === 'link' ? true : isInline(element);};复制代码
const insertLine = (editor) => { let editorEnd = Editor.end(editor, []); let selection = editor.selection; let [selectionStart, selectionEnd] = Range.edges(selection); let isEditorEnd = false; if (selection) { if (Point.equals(editorEnd, selectionEnd)) { isEditorEnd = true; } } if (Point.equals(selectionStart, selectionEnd) && isEditorEnd) { //最后一行 if (editorEnd.offset === 0 && editorEnd.path.length === 2 && editorEnd.path[1] === 0) { Transforms.removeNodes(editor, { at: selection }); } } Transforms.insertNodes(editor, { type: 'hr', children: [{ text: '' }] }); if (isEditorEnd) { Transforms.insertNodes(editor, { type: 'paragraph', children: [{ text: '' }] }); } else { let anchor = editor.selection.anchor; let path = anchor.path.map((item) => item); path[path.length - 2]++; Transforms.select(editor, { path, offset: 0 }); }}; //hr组件没有内容可以编辑,所以重写isVoid editor.isVoid = (element) => { return element.type === 'hr' ? true : isVoid(element); }; //Element contentEditable={false} 控制不能编辑,image,video,mention都是通过配套设置的 const HR = React.memo(({ attributes, children, element }) => { const selected = useSelected(); const editor = useSlate(); const fn = () => { Transforms.removeNodes(editor); }; return ( <div contentEditable={false} {...attributes}> <div className={'slate-hr' + (selected ? ' active' : '')}> <div className="slate-content-toolbar" onClick={fn}> <a></a> </div> </div> {children} </div> ); });复制代码
<Editable className="slate-content" renderElement={renderElement} renderLeaf={renderLeaf} placeholder="Enter some rich text…" spellCheck={false} autoFocus onCompositionEnd={(e) => { Transforms.setNodes( editor, { key: +new Date() }, { match: Text.isText } ); }}/>复制代码
各方面用起来的确是瞒爽的,但是github上没找到给力的项目,真的很尴尬
现在前端 Low Code, No Code, AI Code 正在流行,个人觉得所见即所得的编辑交互更加友好。大厂阿里的语雀编辑器不知道有没开源计划,期待。
特此悼念下美大,每次都感概大神的技术,努力和运气,每个大神背后肯定付出了更多。人生只有一次,想通过技术走上人生巅峰的小伙伴们,也多注意休息,锻炼身体。