开源一个 React 技术栈的高扩展性富文本编辑器
时间: 2020-08-20来源:V2EX
前景提要
最近我花了点时间,把之前使用旧版的 slate 框架积累的一些经验整理了下,开源一个基于 slate 框架的 react 技术栈的高扩展性的富文本编辑器。
它的高扩展性主要在于: 支持自定义工具栏; 支持自定义节点渲染 ;
简要 demo 如下 import * as React from "react"; import ReactDom from "react-dom"; import EasyEditor from "@camol/easy-editor"; class Editor extends React.Component { html = ""; handleChange = (v: any) => { console.log("change=>>>", v); if (this.editorRef.current) { // value to html console.log(this.editorRef.current.convertor.serialize(v.change.value)); } }; render() { return <EasyEditor value={"<p>123</p>"} onChange={this.handleChange} />; } } ReactDom.render(<Editor />, document.getElementById("root"));
value 支持 slate 的 Value 实例,也支持 html 。所以,你可以调用 value.toJSON() 取得 json 格式的数据 或者转成 html 存入数据库,回显时可以直接使用。
支持自定义工具栏
目前,编辑器已经内置了一些工具,如文字加粗、斜体、下划线、文字居中等功能。支持图片和视频的插入,资源地址可以通过 beforeUpload 自定义上传逻辑。从剪贴板内复制粘贴图片(包括 word 内复制)等上传文件部分都会尝试调用该函数以获取上传后的资源地址。不使用自定义上传时,图片地址默认使用 base64 格式。
悬浮工具栏,考虑到选中不同节点时的渲染不同,还没考虑好如何设计,暂时注释掉了这部分功能,后面会完善。
// 自定义 插入视频的操作按钮 class AudioControl extends React.Component { inputRef = React.createRef(); handleClick = () => { if (inputRef.current) { inputRef.current.click(); } }; handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { const file = e.target.files[0]; e.target.value = ""; if (file) { if (this.props.beforeUpload) { let url = await this.props.beforeUpload(file); if (url) { let change = this.props.change.focus().insertInline({ object: "inline", type: "audio", isVoid: true, data: { src: url, }, }); this.props.update(change); } } } }; render() { return ( <span onMouseDown={this.handleClick}> <span className="tool-insert-video" /> <input type="file" style={{ width: 0, height: 0, opacity: 0 }} ref={this.inputRef} onChange={this.handleChange} /> </span> ); } } <EasyEditor value={"<p>123</p>"} onChange={this.handleChange} controls={[ ["bold", "u", "image"], [ { type: "audio", component: (change, update, beforeUpload) => { return ( <AudioControl change={change} update={update} beforeUpload={beforeUpload} /> ); }, }, ], ]} />
支持自定义节点渲染
使用自定义节点渲染,可以实现一些高级功能,如图片拖拽调整大小,图片悬浮、左环绕、右环绕等功能,或者表格的拖拽调整等,又或者是类似石墨文档等添加文件附件,展示在文档中的功能。前面部分功能已经在编辑器内实现了。
这里我简要展示下如何自定义渲染 audio 标签: import * as React from "react"; import { DefaultTreeElement } from "parse5"; const plugin = { type: "node", // node, mark object: "inline", // block, inline nodeType: "super-audio", // 自定义节点类型 // 自动解析 html 中 audio 标签,生成 super-audio 节点 importer(el: DefaultTreeElement, next: Function): any { if (el.tagName.toLowerCase() === "audio") { return { object: "inline", // block 、inline, type: "super-audio", isVoid: true, data: { src: el?.attrs?.find((n) => n.name === "src")?.value, }, nodes: next(el.childNodes), }; } }, // 调用 editor.convertor.serialize(value) 会调用该方法将 super-audio 节点 转成 对应的 html 存入数据库 exporter(node: any, children: any): any { let { className, src } = node.data.toJS(); return <audio src={src} className={className}></audio>; }, // 自定义渲染方式 render( editor: any, props: { attributes: any; children: any; node: any; isSelected: any } ): any { // @ts-ignore const { attributes, children, node, isSelected } = props; const src = node.data.get("src"); return ( <span {...attributes}> <audio src={src} controls> {children} </audio> </span> ); }, }; export default plugin; <EasyEditor value="<audio src='xxxxx.mp3'></audio><p> </p>" ... plugins={[audioPlugin]} />
目前编辑器中的视频播放插件就是使用该特性实现的,集成了 plyr-react ,支持 mp4 、webm (其他格式后面会支持)。
求支持
虽然可能还有些问题,但我后面会长期维护的,希望对需要的同学们有帮助 :)。
最后贴一下该项目的 github 地址,求支持,求 star !
https://github.com/kanweiwei/easy-editor

科技资讯:

科技学院:

科技百科:

科技书籍:

网站大全:

软件大全:

热门排行