vditor 更好用的 markdown 编辑器组件

介绍

这个编辑器组件功能很多,支持大纲、数学公式、流程图等,基本上能想到的都包含了,开箱即用。编辑体验良好,移动设备使用体验也不错。

这是个中文项目,已持续多年迭代,社区稳定,文档易懂,Demo 多样,使用 TS 开发,类型友好。

https://github.com/Vanessa219/vditor

安装使用

npm install vditor --save

使用:

React 包装组件

在官网 React 示例的基础上,我进行了以下封装:

  • 支持传入参数,不做过多定制化,由外部控制
  • 模仿 tui.editor 的用法,支持通过 ref 来获取 vditor 实例,方便外部操作
export interface IVditorEditorProps {
  options: IOptions;
}

export interface IVditorEditorRef {
  getInstance: () => Vditor | null;
}

const VditorEditor: ForwardRefRenderFunction<IVditorEditorRef, IVditorEditorProps> = (
  { options },
  ref,
) => {
  const domRef = useRef<HTMLDivElement>(null);
  const vditorRef = useRef<Vditor | null>(null);
  const optionsRef = useRef(options);

  useEffect(() => {
    if (domRef.current) {
      vditorRef.current = new Vditor(domRef.current, optionsRef.current);
    }
    return () => {
      if (vditorRef.current) {
        vditorRef.current.destroy();
      }
    };
  }, []);

  function getInstance() {
    return vditorRef.current;
  }

  useImperativeHandle(ref, () => {
    return { getInstance };
  });

  return <div ref={domRef}></div>;
};

export default forwardRef(VditorEditor);

编辑器设置记录

以下内容都在编辑器初始化时传入的 options 参数声明。

配置 tab 使得可以方便地编辑代码,不然点击 tab 后可能会出现不符合预期的效果。

tab: '  '

历史记录间隔,默认是 800 毫秒,缩短间隔时间可避免一次性回退过多内容。

undoDelay: 400

初始化后,赋予默认值:

after: () => {
  if (value) {
    instance.setValue(value); 
  }
}

内容更新回调:

input(value: string) {
  onChange(value);
}

自定义单图片上传:

upload: {
  accept: 'image/*',
  multiple: false,
  async handler(files) {
    let file = files[0];
    let url = await uploadFunc(file);
    let name = file.name;
    let code = `\n![${name}](${url})`;
    instance.insertValue(code);
    return null
  },
},

由于按需加载的机制,vditor 使用了 cdn,但可能不太稳定,可进行自建 cdn,将 dist 目录放到自定义的一个目录下,需包含 dist 本身:

cdn: cdnPath,
theme: {
  path: `${cdnPath}/dist/css/content-theme`,
  current: 'light',
},

模式切换与表格编辑

可选模式有:sv 分屏预览, ir 即时渲染, wysiwyg 所见即所得;

  • 即时渲染、所见即所得模式,有大纲,可快速定位到某个小节进行修改。
  • 表格编辑适合到所见即所得模式下进行编辑,有上、下、左、右插入行列的选项
  • sv 模式下问题相对较多,vditor 官方对 sv 模式也不太维护,使用体验一般。

所以使用模式为:默认使用 ir 即时渲染模式,表格编辑时使用 wysiwyg 所见即所得模式,查看 markdown 源代码时使用 sv 分屏预览模式。

一些使用笔记

移动端窗口小,可切换为全屏后,使用即时渲染模式,也有很好的编辑体验,大纲在移动端会自动隐藏。

复制代码片段、链接时编辑器会进行处理,如代码片段会自动加 ··· ,即使已经在代码片段内,这样就会导致错乱。此时使用 shift + ctrl + v 粘贴进来即可,不会特殊处理。

在 ir 即时渲染模式中,代码块后如果是标题,标题前无法插入内容。可在下一行标题前点击回车,然后输入内容,即可继续编写本节内容。全文最后段代码,在代码最后一行按方向键下即可进入新的一行。

markdown 文本渲染

组件还提供了一些静态方法,如对页面中的 Markdown 进行渲染时可直接调用 preview 方法。

基于这个方法,可再封装一个 React 渲染组件,支持 value 改变后重新渲染:

export interface IVditorPreviewProps {
  value: string | undefined;
}
const VditorPreview: FC<IVditorPreviewProps> = ({ value }) => {
  const domRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (domRef.current && value) {
      Vditor.preview(domRef.current, value);
    }
  }, [value]);

  return <div ref={domRef}></div>;
};
本文收录于专栏
收集一些好用的前端开源库,主要是 npm 包