React - markdown第三方库(文件上传下载)

576 阅读1分钟

1 推荐md-editor-rt

说明文档地址:(imzbf.github.io/md-editor-r…)

github:(github.com/imzbf/md-ed…)

推荐理由:

  • 一款很健全的markdown第三方库,文档说明详细
  • 兼容react,typescript
  • 虽然 star少,但是遇到问题作者还是很愿意回答
  • 代码theme和预览theme还是很多可选友好的。
  • 可拓展性强

2 文件上传下载

2.1 下载的解决方式

目前主流的上传下载后端接口都需要请求接口带token,内部的md转html我是没有过多的研究,所以我是让后端把下载接口加入白名单中,免去token认证,思路是利用markdown的链接,点击给a标签加入_black属性.

具体配置如下:

import { config } from 'md-editor-rt';

// 修改配置
config({
  markdownItConfig(md) {
    md.use(TargetBlankExtension);
  },
});

const TargetBlankExtension = (md: markdownit) => {
  const defaultRender =
    md.renderer.rules.link_open ||
    function (tokens, idx, options, env, self) {
      return self.renderToken(tokens, idx, options);
    };

  md.renderer.rules.link_open = function (tokens, idx, options, env, self) {
    const aIndex = tokens[idx].attrIndex('target');

    if (aIndex < 0) {
      tokens[idx].attrPush(['target', '_blank']);
    } else {
      // @ts-ignore
      tokens[idx].attrs[aIndex][1] = '_blank';
    }

    // pass token to default renderer.
    return defaultRender(tokens, idx, options, env, self);
  };
};

这样就可以实现a标签加上_blank属性

2.2 上传组件

这个第三方库没有提供上传的按钮,但是支持自定义拓展, 具体可以看文档:自定义工具栏自定义工具栏例子

上传接口就略过了,没啥好说的,formData然后提交。

上传工具栏组件:

import { OnUploadFileFun } from '@/components/MdEditor/data';
import { FileAddOutlined } from '@ant-design/icons';
import { Upload } from 'antd';
import { InsertContentGenerator, NormalToolbar } from 'md-editor-rt';
import type { UploadRequestOption } from 'rc-upload/lib/interface';

interface MarkExtensionProp {
  onInsert: (generator: InsertContentGenerator) => void;
}

const UploadFile = (props: MarkExtensionProp & { onUploadFileFun: OnUploadFileFun }) => {
  const uploadFileHandler = (files: UploadRequestOption) => {
    const file = files.file as File;
    // 1. 校验文件大小,确保不超过1MB
    // const maxSize = 1 * 1024 * 1024; // 1MB
    // if (file.size > maxSize) {
    //   console.log('文件大小不能超过1MB');
    //   message.error('文件大小不能超过1MB');
    //   return;
    // }

    const form = new FormData();
    form.append('file', file);
    if (props.onUploadFileFun.formData) {
      Object.keys(props.onUploadFileFun.formData).forEach((key) => {
        // @ts-ignore
        form.append(key, props.onUploadFileFun.formData[key]);
      });
    }
    props.onUploadFileFun.func(form).then((url) => {
      const generator: InsertContentGenerator = () => {
        return {
          targetValue: `[文件:${file.name}-点击下载](${url})`,
          select: true,
          deviationStart: 0,
          deviationEnd: 0,
        };
      };

      props.onInsert(generator);
    });
  };

  return (
    <NormalToolbar
      title="上传文件"
      onClick={() => {}}
      trigger={
        <Upload showUploadList={false} customRequest={uploadFileHandler}>
          <FileAddOutlined
            style={{
              width: '30px',
              height: '30px',
              fontSize: '20px',
            }}
          />
        </Upload>
      }
    ></NormalToolbar>
  );
};

export default UploadFile;

这里接收了一个默认上传方法,如果有传的话就按你自定义的上传方法走,否则走默认定义的上传方法。

外部调用:

import UploadFile from '@/components/MdEditor/component/UploadFile';
import '@/styles/md-editor/index.css';
import { ExposeParam, InsertContentGenerator, MdEditor } from 'md-editor-rt';
import { EditorProps } from 'md-editor-rt/lib/types/MdEditor/type';
import React, { useCallback, useEffect, useState } from 'react';

const MarkDownEditor: React.FC = () => {
  const [mdValue, setMdValue] = useState<string>('');
  useEffect(() => {
    setMdValue(customProp.initContent || '');
  }, [customProp.initContent]);

  const onInsert = useCallback((generator: InsertContentGenerator) => {
    editorRef.current?.insert(generator);
  }, []);

  return (
    <MdEditor
      style={{ height: '700px' }}
      ref={editorRef}
      modelValue={mdValue}
      onChange={setMdValue}
      previewTheme="default"
      defToolbars={[
        <UploadFile
          onInsert={onInsert}
          key="uploadFile"
        ></UploadFile>,
      ]}
    />
  );
};

export default MarkDownEditor;