Javascript

slate.js从入门到放弃

本文主要是介绍slate.js从入门到放弃,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
公司组织的活动,发篇博文。前段时间正好项目需要富文本编辑器。同事用的draft.js,用起来麻烦。谷歌了下有啥别的解决方案,发现了slate.js,正好语雀底层也是用的slate.js定制的,就倒腾了起来。

1.官网 https://docs.slatejs.org/

slate.js 和 Draft.js, Prosemirror and Quill一样,都是基于结构化对象,渲染富文本编辑内容。简单的说,富文本编辑器的value不再是html,而是State Object.

e文不大好的同学可以看看中文的文档, github.com/loveloki/sl…

本来还想复制黏贴翻译一波官网的,有中文的大家就自己看下学习下吧。

看完walkthroughs,真的感觉既简单又实用,代码还是react hook,大厂还在用,就这个了买它买它~~当然还是很耐心的看完了ConceptsAPI

API章节没有中文翻译,大家可以锻炼下自己,看着这么详细的API,那不是更该支持一波

  1. Transforms  转换是操作文档的辅助函数(Node 结点,Selection 选择区,Text 文本)

  2. Nodes Editor的几个方法比较常用,代码中需要通过函数重写的方式进行扩展

  3. Locations 位置相关的api

  4. Refs 没看懂

  5. Miscellaneous createEditor()

2.入门 - 编辑器DEMO实例

GitHub上搜了一波,看见了这个项目github.com/Canner/cann…,但是这个项目都是2年前的了(难道是我闭门太9了,以前都没听过slate.js)

看着官网的例子,感觉写个简单的应该不难,正好想认真学习下,也方便定制编辑器。写了个简单的实例,github.com/legu2009/sl…,公司组件库用的Braft Editor,所以UI借鉴了下(大家都懂的),实在是icon折腾了大半天,没有找到开箱即用的。组件用react hook写的

总结下踩的小坑

  1. Toolbar Button点击,editor会失去焦点,通过onKeyDown event.preventDefault()处理
  2. 判断Selection的状态,Button选中状态。对于Text,通过 marks = Editor.marks(editor) 获取当前的状态判断。对于Element,通过 Editor.nodes(editor, { match: (n) => n.type === 'xxx' })迭代进行查找
  3. Link DropDown 里面有个input,没办法onKeyDown event.preventDefault() 处理,所以通过 tmpSelection 缓存,Transforms 之前通过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);};复制代码

  4. Link 的交互和别的富文本差别  DropDown显示的时候,如果是选择了一段文本,则默认先加个空链接,在编辑url的时候,用户也能知道设置的文本。如果选择的内容和一段链接有交集的话,设置新的链接会把原来的清除
  5. 水平线HR 判断如果是文章末尾的话,就多插入一行。并且选择区移动到插入hr的后一个位置,方便删除。API不熟,可能有更简便的写法

    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>&#xe9ac;</a>
                    </div>
                </div>
                {children}
            </div>
        );
    });复制代码
  6. 网上的中文输入法问题(忘记先Issues里搜下)。看了下页面错误效果,中文输入法会自己插入内容 和 State渲染出来的不一致,导致React VDom 和 Dom 不一致。我的解法是在onCompositionEnd的时候,给Text设置个Key,让编辑的Text触发重新渲染

    <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 }        );    }}/>复制代码

  7. 图片功能 没有实现。图片涉及到上传接口功能。
  8. 表情功能 没有实现。只是写了个简单的插入@aaa,看看效果。项目中想是作为占位符替换文本的功能。
  9. 表格功能 没有实现。实在是太复杂了,面临的问题也都很难实现。包括表格选择-编辑状态交互,表格嵌套,表格合并列,合并行等等。只是试了下表格嵌套的效果。

3.放弃

各方面用起来的确是瞒爽的,但是github上没找到给力的项目,真的很尴尬

  1. 个人时间有限,能力也有限,在遇到Table组件这种复杂交互的开发,真的太难了。
  2. slate.js对IE的支持不好,MAC用多了,犯了个低级错误,选型的时候忘看IE兼容性了。slate-react用了比较多的IE不支持的API。虽然我觉得让用户装Chrome很合理,但是大家懂的,说服产品经理比说服自己难多了。
  3. 编辑器的dom结构很复杂,一个文本有这么多node,需要定制slate-react
  4. 中文输入法的问题,我不知道有没完全解决

4.其他

现在前端 Low Code, No Code, AI Code 正在流行,个人觉得所见即所得的编辑交互更加友好。大厂阿里的语雀编辑器不知道有没开源计划,期待。

特此悼念下美大,每次都感概大神的技术,努力和运气,每个大神背后肯定付出了更多。人生只有一次,想通过技术走上人生巅峰的小伙伴们,也多注意休息,锻炼身体。



这篇关于slate.js从入门到放弃的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!