• 一款好看的markdown编辑器:md-editor-v3


    md-eidtor-v3地址

    md-editor-v3 的 github地址 及使用文档
    md-editor-v3 预览效果地址

    其它markdown编辑器

    mavon-editor文本编辑器上传图片用法
    Vue富文本编辑器-mavon-editor文本编辑器
    v-md-editor使用 & 生成el-tree文章目录滚动跟随高亮

    🎄 md-editor-v3

    English | 中文

    vue3 环境的 Markdown 编辑器,使用 jsxtypescript 语法开发,支持在 tsx 项目使用。

    ⭐️ 功能一览

    • 快捷插入内容工具栏、编辑器浏览器全屏、页面内全屏等;
    • 内置的白色主题和暗黑主题,支持绑定切换;
    • 支持快捷键插入内容; 支持使用 prettier 格式化内容(使用 CDN 方式引入,只支持格式化 md 内容,可在代码内设置关闭);
    • 多语言,支持自行扩展语言;
    • 粘贴上传图片,图片裁剪上传;
    • 仅预览模式(不显示编辑器,只显示 md 预览内容,无额外监听);
    • 预览主题,内置defalutvuepressgithubcyanosismk-cutesmart-blue 6 种预览主题(不完全相同),支持自定义主题(参考文档 demo 页示例);
    • mermaid绘图(>=1.8.0),katex数学公式(>=1.9.0);
    • 自定义工具栏顺序或显示,自定义扩展工具栏(支持点击类型、下拉菜单类型及弹窗类型)等。
    • 按需引用(>=4.0.0)。

    📦 安装

    yarn add md-editor-v3
    
    • 1

    使用语言、预览主题扩展库:

    yarn add @vavt/md-editor-extension
    
    • 1

    更多使用及贡献方式参考:md-editor-extension

    💡 用法

    ✍🏻 编辑器模式

    <template>
      <MdEditor v-model="text" />
    template>
    
    <script setup>
    import { ref } from 'vue';
    import { MdEditor } from 'md-editor-v3';
    import 'md-editor-v3/lib/style.css';
    
    const text = ref('# Hello Editor');
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    v4.0.0开始,内部组件支持按需引用。

    如果页面存在多个编辑器,请给组件设置不相同的editorId

    📖 仅预览模式

    <template>
      <MdPreview :editorId="id" :modelValue="text" />
      <MdCatalog :editorId="id" :scrollElement="scrollElement" />
    template>
    
    <script setup>
    import { ref } from 'vue';
    import { MdPreview, MdCatalog } from 'md-editor-v3';
    import 'md-editor-v3/lib/preview.css';
    
    const id = 'preview-only';
    const text = ref('# Hello Editor');
    const scrollElement = document.documentElement;
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    🗺 预览图

    | 默认模式 | 暗黑模式 | 仅预览 |
| --- | --- | --- |
| [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dqbbuwp9-1685158108017)(https://imzbf.github.io/md-editor-v3/imgs/preview-light.png)] | [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C7viERoK-1685158108017)(https://imzbf.github.io/md-editor-v3/imgs/preview-dark.png)] | [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j8yYa47E-1685158108022)(https://imzbf.github.io/md-editor-v3/imgs/preview-previewOnly.png)] |

    简单的标记和表情扩展预览

    在这里插入图片描述

    🎁 Apis

    🔖 MdPreivew Props

    名称类型默认值说明
    modelValuestring‘’md 编辑内容,vue 模板支持双向绑定(v-model=“value”)
    themelight | dark‘light’主题切换
    classstring‘’编辑器类名
    languagestring‘zh-CN’内置中英文(‘zh-CN’,‘en-US’),可自行扩展其他语言,同时可覆盖内置的中英文
    editorIdstring‘md-editor-v3’编辑器唯一标识,非必须项,当相同页面存在两个编辑器时,请务必区别该属性
    showCodeRowNumberbooleanfalse代码块是否显示行号
    previewTheme'default' | 'github' | 'vuepress' | 'mk-cute' | 'smart-blue' | 'cyanosis'‘default’预览内容主题,自定义主题规则见下方
    stylestring | CSSProperties{}编辑器内联样式
    noMermaidbooleanfalse如果你不希望使用图表展示内容,可以设置关闭
    noKatexbooleanfalse不使用 katex 展示数学公式
    codeTheme'atom' | 'a11y' | 'github' | 'gradient' | 'kimbie' | 'paraiso' | 'qtcreator' | 'stackoverflow'‘atom’代码块 highlight 样式名称,扩展更多见下方
    mdHeadingId(text: string, level: number, index: number) => string(text) => text标题ID计算方式
    sanitize(html: string) => string(html) => html在每次生成 html 后,通过该方法移除危险内容,比如 xss 相关。
    noIconfontbooleanfalse不插入 iconfont 链接,你可以下载到本地自行引入
    formatCopiedText(text: string) => string(text: string) => text格式化复制代码
    codeStyleReversebooleantrue代码块为暗色背景的预览主题,将代码风格设置为暗色风格
    codeStyleReverseListArray[‘default’, ‘mk-cute’]代码块为暗色背景的预览主题
    noHighlightbooleanfalse永远不高亮代码

    🔩 MdEditor Props

    除去和MdPreivew相同的以外:

    名称类型默认值说明
    pageFullscreenbooleanfalse页面内全屏
    previewbooleantrue是否预览
    htmlPreviewbooleanfalse是否 html 预览(如果是 true,preview 需要设置为 false)
    toolbarsArray[toolbars]选择性展示工具栏,可选内容见下方toolbars
    toolbarsExcludeArray[]选择性不展示工具栏,内容同toolbars
    noPrettierbooleanfalse是否启用 prettier 优化 md 内容
    tabWidthnumber2编辑器 TAB 键位等于空格数
    tableShape[number, number][6, 4]标题栏添加表格时,预设待选表格大小,第一个代表最大列数,第二个代表最大行数。
    placeholderstring‘’
    footersArray<'markdownTotal' | '=' | 'scrollSwitch' | number>[‘markdownTotal’, ‘=’, ‘scrollSwitch’]页脚显示内容,=左右分割,设置为[]不显示页脚
    scrollAutobooleantrue默认左右滚动状态
    noUploadImgbooleanfalse不展示上传图片选项
    autoFocusbooleanfalse文本区域自动获得焦点
    disabledbooleanfalse禁用文本区域
    readOnlybooleanfalse文本区域为只读
    maxLengthnumber文本区域允许的最大字符数
    autoDetectCodebooleanfalse是否启用自动识别粘贴代码类别,目前仅支持从vscode复制的内容

    如果你重新定义了标题,请务必通过mdHeadingId告诉编辑器你生成标题 ID 的算法。以便生成的内部目录能够正确导航。

    『toolbars』
    [
      'bold',
      'underline',
      'italic',
      '-',
      'strikeThrough',
      'title',
      'sub',
      'sup',
      'quote',
      'unorderedList',
      'orderedList',
      'task', // ^2.4.0
      '-',
      'codeRow',
      'code',
      'link',
      'image',
      'table',
      'mermaid',
      'katex',
      '-',
      'revoke',
      'next',
      'save',
      '=',
      'pageFullscreen',
      'fullscreen',
      'preview',
      'htmlPreview',
      'catalog',
      'github'
    ];
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    你可以随意排序工具栏,通过'-'分割两个工具,通过'='实现左右放置!

    你可以自定义工具栏,将defToolbars中自定义工具项的下标穿插在toolbars实现展示(这并不规范),更多请参考文档

    『StaticTextDefaultValue』

    自定义语言,需要替换的下面的全部内容(某些字段若不主动提供,会造成页面不美观):

    export interface ToolbarTips {
      bold?: string;
      underline?: string;
      italic?: string;
      strikeThrough?: string;
      title?: string;
      sub?: string;
      sup?: string;
      quote?: string;
      unorderedList?: string;
      orderedList?: string;
      task?: string; // ^2.4.0
      codeRow?: string;
      code?: string;
      link?: string;
      image?: string;
      table?: string;
      mermaid?: string;
      katex?: string;
      revoke?: string;
      next?: string;
      save?: string;
      prettier?: string;
      pageFullscreen?: string;
      fullscreen?: string;
      catalog?: string;
      preview?: string;
      htmlPreview?: string;
      github?: string;
      '-'?: string;
      '='?: string;
    }
    
    export interface StaticTextDefaultValue {
      // 工具栏hover提示
      toolbarTips?: ToolbarTips;
      // 标题下拉框内容
      titleItem?: {
        h1?: string;
        h2?: string;
        h3?: string;
        h4?: string;
        h5?: string;
        h6?: string;
      };
      imgTitleItem?: {
        link: string;
        upload: string;
        clip2upload: string;
      };
      // 添加链接或图片时弹窗提示
      linkModalTips?: {
        linkTitle?: string;
        imageTitle?: string;
        descLabel?: string;
        descLabelPlaceHolder?: string;
        urlLabel?: string;
        urlLabelPlaceHolder?: string;
        buttonOK?: string;
      };
      // 裁剪图片弹窗提示,v1.2.0
      clipModalTips?: {
        title?: string;
        buttonUpload?: string;
      };
      // 预览代码中复制代码提示
      copyCode?: {
        text?: string;
        successTips?: string;
        failTips?: string;
      };
      mermaid?: {
        // 流程图
        flow?: string;
        // 时序图
        sequence?: string;
        // 甘特图
        gantt?: string;
        // 类图
        class?: string;
        // 状态图
        state?: string;
        // 饼图
        pie?: string;
        // 关系图
        relationship?: string;
        // 旅程图
        journey?: string;
      };
      katex?: {
        // 行内公式
        inline: string;
        // 块级公式
        block: string;
      };
      footer?: {
        markdownTotal: string;
        scrollAuto: string;
      };
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100

    🧵 MdPreview 绑定事件

    名称入参说明
    onHtmlChangedhtml: stringhtml 变化回调事件,用于获取预览 html 代码
    onGetCataloglist: Array获取markdown目录

    🪢 MdEditor 绑定事件

    除去和MdPreivew相同的以外:

    名称入参说明
    onChangevalue: string内容变化事件(当前与textareoninput事件绑定,每输入一个单字即会触发)
    onSavevalue: string, html: Promise保存事件,快捷键与保存按钮均会触发
    onUploadImgfiles: Array, callback: (urls: Array) => void上传图片事件,弹窗会等待上传结果,务必将上传后的 urls 作为 callback 入参回传
    onErrorerr: { name: string; message: string }运行错误反馈事件,目前包括Cropperfullscreenprettier实例未加载完成操作错误
    onBlurevent: FocusEvent输入框失去焦点时触发事件
    onFocusevent: FocusEvent输入框获得焦点时触发事件

    🎍 插槽

    名称类型默认值说明
    defToolbarsArraynull使用内置的组件自定义扩展工具栏
    defFootersArraynull自定义扩展页脚

    使用内置的 3 个组件(说明见下方),自定义工具栏,简单示例:

    <template>
      <MdEditor>
        <template #defToolbars>
          <NormalToolbar title="mark" @onClick="handler">
            <template #trigger>
              <svg class="md-editor-icon" aria-hidden="true">
                <use xlink:href="#md-editor-icon-mark">use>
              svg>
            template>
          NormalToolbar>
        template>
      MdEditor>
    template>
    
    <script setup lang="ts">
    import { MdEditor, NormalToolbar } from 'md-editor-v3';
    import 'md-editor-v3/lib/style.css';
    
    const handler = () => {
      console.log('NormalToolbar clicked!');
    };
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    🤱🏼 实例暴露

    编辑器暴露了若干方法在组件实例上,用来快捷监听编辑器内部状态或对调整内部状态。

    <template>
      <MdEditor ref="editorRef" />
    template>
    
    <script setup lang="ts">
    import { ref, onMounted } from 'vue';
    import { MdEditor } from 'md-editor-v3';
    import type { ExposeParam } from 'md-editor-v3';
    import 'md-editor-v3/lib/style.css';
    
    const editorRef = ref<ExposeParam>();
    
    onMounted(() => {
      editorRef.value?.on('catalog', console.log);
    });
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    触发方法不设置入参切换为相反状态

    👂🏼 on

    监听编辑器内部状态,包括:屏幕全屏、浏览器全屏、预览文本、预览 html、目录等。

    • pageFullscreen

      editorRef.value?.on('pageFullscreen', (status) => console.log(status));
      
      • 1
    • fullscreen

      editorRef.value?.on('fullscreen', (status) => console.log(status));
      
      • 1
    • preview

      editorRef.value?.on('preview', (status) => console.log(status));
      
      • 1
    • htmlPreview

      editorRef.value?.on('htmlPreview', (status) => console.log(status));
      
      • 1
    • catalog

      editorRef.value?.on('catalog', (status) => console.log(status));
      
      • 1

    💻 togglePageFullscreen

    切换页面内全屏。

    editorRef.value?.togglePageFullscreen(true);
    
    • 1

    🖥 toggleFullscreen

    切换屏幕全屏。

    editorRef.value?.toggleFullscreen(true);
    
    • 1

    📖 togglePreview

    切换是否显示预览。

    editorRef.value?.togglePreview(true);
    
    • 1

    📼 toggleHtmlPreview

    切换是否显示 html 预览。

    editorRef.value?.toggleHtmlPreview(true);
    
    • 1

    🧬 toggleCatalog

    切换是否显示目录。

    editorRef.value?.toggleCatalog(true);
    
    • 1

    💾 triggerSave

    触发保存。

    editorRef.value?.triggerSave();
    
    • 1

    💉 insert

    手动向文本框插入内容。

    /**
     * @params selectedText 选中的内容
     */
    editorRef.value?.insert((selectedText) => {
      /**
       * @return targetValue    待插入内容
       * @return select         插入后是否自动选中内容
       * @return deviationStart 插入后选中内容鼠标开始位置
       * @return deviationEnd   插入后选中内容鼠标结束位置
       */
      return {
        targetValue: `${selectedText}`,
        select: true,
        deviationStart: 0,
        deviationEnd: 0
      };
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    示例参考文档源码中的扩展组件

    🎯 focus

    手动聚焦输入框。

    editorRef.value?.focus();
    
    • 1

    💴 编辑器配置

    使用config(option: ConfigOption)方法,可以对构建实例进行定制。

    • codeMirrorExtensions: 根据主题和内部默认的 codeMirror 扩展自定义新的扩展。

      使用示例:编辑器默认不显示输入框的行号,需要手动添加扩展

      import { config } from 'md-editor-v3';
      import { lineNumbers } from '@codemirror/view';
      
      config({
        codeMirrorExtensions(_theme, extensions) {
          return [...extensions, lineNumbers()];
        }
      });
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
    • markdownItConfig: 自定义 markdown-it 核心库扩展、属性等。

      使用示例:配置使用markdown-it-anchor并在标题右侧显示一个超链接符号

      import { config } from 'md-editor-v3';
      import ancher from 'markdown-it-anchor';
      
      config({
        markdownItConfig(mdit) {
          mdit.use(ancher, {
            permalink: true
          });
        }
      });
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
    • editorConfig: 编辑器常规配置,语言、mermaid默认模板和渲染延迟:

      import { config } from 'md-editor-v3';
      
      config({
        editorConfig: {
          // 语言
          languageUserDefined: { lang: StaticTextDefaultValue },
          // mermaid模板
          mermaidTemplate: {
            flow: `flow tempalte`,
            ...more
          },
          // 输入渲染延迟,默认500ms。当仅预览模式时,未设置此项默认0ms
          renderDelay: 500
        }
      });
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
    • editorExtensions: 类型如下,用于配置编辑器内部的扩展

      import { config } from 'md-editor-v3';
      
      config({
        editorExtensions: { iconfont: 'https://xxx.cc' }
      });
      
      • 1
      • 2
      • 3
      • 4
      • 5
      『EditorExtensions』
      export interface EditorExtensions {
        highlight?: {
          instance?: any;
          js?: string;
          css?: {
            [key: string]: {
              light: string;
              dark: string;
            };
          };
        };
        prettier?: {
          standaloneJs?: string;
          parserMarkdownJs?: string;
        };
        cropper?: {
          instance?: any;
          js?: string;
          css?: string;
        };
        iconfont?: string;
        screenfull?: {
          instance?: any;
          js?: string;
        };
        mermaid?: {
          instance?: any;
          js?: string;
        };
        katex?: {
          instance?: any;
          js?: string;
          css?: string;
        };
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35

    🪡 快捷键

    主要以CTRL搭配对应功能英文单词首字母,冲突项添加SHIFT,再冲突替换为ALT

    请注意,快捷键仅在输入框获取到焦点时可用!

    键位功能说明
    TAB空格通过tabWidth属性预设 TAB 键位新增空格长度,默认 2,支持多行
    SHIFT + TAB取消空格同上,一次取消两个空格,支持多行
    CTRL + C复制选中时复制选中内容,未选中时复制当前行内容
    CTRL + X剪切选中时剪切选中内容,未选中时剪切当前行
    CTRL + D删除选中时删除选中内容,未选中时删除当前行
    CTRL + S保存触发编辑器的onSave回调
    CTRL + B加粗**加粗**
    CTRL + U下划线下划线
    CTRL + I斜体*斜体*
    CTRL + 1-61-6 级标题# 标题
    CTRL + ↑上角标上角标
    CTRL + ↓下角标下角标
    CTRL + O有序列表1. 有序列表
    CTRL + L链接[链接](https://github.com/imzbf/md-editor-v3)
    CTRL + Z撤回触发编辑器内内容撤回,与系统无关
    CTRL + SHIFT + S删除线~删除线~
    CTRL + SHIFT + U无序列表- 无序列表
    CTRL + SHIFT + C块级代码多行代码块
    CTRL + SHIFT + I图片链接![图片](https://imzbf.github.io/md-editor-v3/imgs/preview-light.png)
    CTRL + SHIFT + Z前进一步触发编辑器内内容前进,与系统无关
    CTRL + SHIFT + F美化内容
    CTRL + ALT + C行内代码行内代码块
    CTRL + SHIFT + ALT + T表格|表格|

    🪤 内部组件

    按需引入内部扩展组件:

    
    
    • 1
    • 2
    • 3

    使用参考:文档页面

    🐣 普通扩展工具栏

    NormalToolbar

    • props

      • title: string,非必须,作为工具栏上的 hover 提示。
    • events

      • onClick: (e: MouseEvent) => void,必须,点击事件。
    • slots

      • trigger: string | JSX.Element,必须,通常是个图标,用来展示在工具栏上。

    🐼 下拉扩展工具栏

    DropdownToolbar

    • props

      • title: string,非必须,作为工具栏上的 hover 提示。
      • visible: boolean,必须,下拉状态。
    • events

      • onChange: (visible: boolean) => void,必须,状态变化事件。
    • slots

      • trigger: string | JSX.Element,必须,通常是个图标,用来展示在工具栏上。
      • overlay: string | JSX.Element,必须,下拉框中的内容。

    🦉 弹窗扩展工具栏

    ModalToolbar

    • props

      • title: string,非必须,作为工具栏上的 hover 提示。
      • modalTitle: string,非必须,弹窗的标题。
      • visible: boolean,必须,弹窗显示状态。
      • width: string,非必须,弹窗宽度,默认auto
      • height: string,同width
      • showAdjust: boolean,非必须,是否显示弹窗全屏按钮。
      • isFullscreen: boolean,显示全屏按钮时必须,弹窗全屏状态。
    • events

      • onClick: () => void,必须,工具栏点击事件。
      • onClose: () => void,必须,弹窗点击关闭事件。
      • onAdjust: (val: boolean) => void,弹窗全屏按钮点击事件。
    • slots

      • trigger: string | JSX.Element,必须,通常是个图标,用来展示在工具栏上。
      • overlay: string | JSX.Element,必须,下拉框中的内容。

    🐻 目录导航

    MdCatalog

    • props

      • editorId: string,必须,对应编辑器的editorId,在内部注册目录变化监听事件。
      • class: string,非必须,目录组件最外层类名。
      • mdHeadingId: MdHeadingId,非必须,特殊化编辑器标题的算法,与编辑器相同。
      • scrollElement: string | HTMLElement,非必须,为字符时应是一个元素选择器。仅预览模式中,整页滚动时,设置为document.documentElement
      • theme: 'light' | 'dark',非必须,当需要切换主题时提供,同编辑器的theme
      • offsetTop: number,非必须,标题距离顶部该像素时高亮当前目录项,默认 20 像素。
      • scrollElementOffsetTop: number,非必须,滚动区域的固定顶部高度,默认 0。
    • events

      • onClick: (e: MouseEvent, t: TocItem) => void,非必须,导航点击事件。

    🗂 部分示例

    🎸 Jsx 模板

    import { defineComponent, reactive } from 'vue';
    import { MdEditor } from 'md-editor-v3';
    import 'md-editor-v3/lib/style.css';
    
    export default defineComponent({
      setup() {
        const md = reactive({
          text: '# Hello Editor'
        });
        return () => (
          <MdEditor modelValue={md.text} onChange={(value) => (md.text = value)} />
        );
      }
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    🥹 上传图片

    默认可以选择多张图片,支持粘贴板上传图片。

    注意:粘贴板上传时,如果是网页上的 gif 图,无法正确上传为 gif 格式!

    <template>
      <MdEditor v-model="text" @onUploadImg="onUploadImg" />
    template>
    
    <script setup>
    import { ref } from 'vue';
    import axios from 'axios';
    import { MdEditor } from 'md-editor-v3';
    import 'md-editor-v3/lib/style.css';
    
    const text = ref('# Hello Editor');
    
    const onUploadImg = async (files, callback) => {
      const res = await Promise.all(
        files.map((file) => {
          return new Promise((rev, rej) => {
            const form = new FormData();
            form.append('file', file);
    
            axios
              .post('/api/img/upload', form, {
                headers: {
                  'Content-Type': 'multipart/form-data'
                }
              })
              .then((res) => rev(res))
              .catch((error) => rej(error));
          });
        })
      );
    
      callback(res.map((item) => item.data.url));
    };
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    🧙‍♂️ 调整编辑器样式

    2.x 使用 css 变量定义了大部分内容:

    .css-vars(@isDark) {
      --md-color: if(@isDark, #999, #222);
      --md-hover-color: if(@isDark, #bbb, #000);
      --md-bk-color: if(@isDark, #000, #fff);
      --md-bk-color-outstand: if(@isDark, #111, #f6f6f6);
      --md-bk-hover-color: if(@isDark, #1b1a1a, #f5f7fa);
      --md-border-color: if(@isDark, #2d2d2d, #e6e6e6);
      --md-border-hover-color: if(@isDark, #636262, #b9b9b9);
      --md-border-active-color: if(@isDark, #777, #999);
      --md-modal-mask: #00000073;
      --md-scrollbar-bg-color: if(@isDark, #0f0f0f, #e2e2e2);
      --md-scrollbar-thumb-color: if(@isDark, #2d2d2d, #0000004d);
      --md-scrollbar-thumb-hover-color: if(@isDark, #3a3a3a, #00000059);
      --md-scrollbar-thumb-active-color: if(@isDark, #3a3a3a, #00000061);
    }
    
    .md-editor {
      .css-vars(false);
    }
    
    .md-editor-dark {
      .css-vars(true);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    只需要调整对应的 css 变量,比如调整暗夜模式下的背景:

    .md-editor-dark {
      --md-bk-color: #333 !important;
    }
    
    • 1
    • 2
    • 3
  • 相关阅读:
    WebAssembly — 概览
    IPEmotion曲线平滑计算
    网站速度测试和优化方案
    银行卡四要素API接口的验证流程
    某基金投资公司绩效考核设计项目成功案例纪实
    Educational Codeforces Round 17 ACD
    Qt基于Qml超链接使用
    SKEP Senta代码 finetune训练步骤 记录
    Python—argparse模块
    Opencv学习笔记(十二):图片腐蚀和膨胀操作
  • 原文地址:https://blog.csdn.net/qq_16992475/article/details/130899269