14

来康康vue3环境下的markdown编辑器md-editor-v3吧,支持tsx,暗黑模式哦~

 3 years ago
source link: https://segmentfault.com/a/1190000040352568
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

来康康vue3环境下的markdown编辑器md-editor-v3吧,支持tsx,暗黑模式哦~

发布于 8 分钟前

这一切都源于在开发vue3-admin的demo内容时,没有合适的编辑器组件。

仅支持 vue3 项目下使用,使用 jsx 语法开发,支持在 tsx 项目使用。为了减小插入,没有使用less.modifyVars方法来切换主题,而采用了替换 class 名称的方式。

代码仓库:md-editor-v3

  1. 快捷插入内容工具栏、编辑器浏览器全屏、页面内全屏等;
  2. 内置的白色主题和暗黑主题,支持绑定切换;
  3. 支持快捷键插入内容;
  4. 支持使用 prettier 格式化内容(使用 CDN 方式引入,只支持格式化 md 内容,可在代码内设置关闭);
  5. 支持多语言,支持自行扩展语言;
  6. 支持复制粘贴上传图片;

更多功能待后续更新,若有想要的功能未开发,请留言~

默认模式下:

暗黑模式下:

主题跟随前往vue3-admin尝试~~

编辑器主页演示没开发完~~~

注意在 jsx 下需使用 modelValue 配合 onChange 方法完成数据绑定,在 vue 模板语法下,可以直接使用 v-modal 指令~

props

名称类型默认值说明modelValueString''md 编辑内容,vue 模板支持双向绑定(v-model="value")editorClassString''编辑器最外层样式hljsObjectnull项目中使用到了 highlight,可将实例直接传递,生产环境则不会请求 CDN,需要手动导入支持的高亮代码样式highlightJsStringhighlight.jshighlightJs CDNhighlightCssStringatom-one-dark预览高亮代码样式historyLengthNumber10最大记录操作数(太大会占用内存)pageFullScreenBooleanfalse浏览器内全屏previewBooleantrue预览模式htmlPreviewBooleanfalsehtml 预览languageString'zh-CN'内置中英文('zh-CN','en-US'),可自行扩展其他语言,同时可覆盖内置的中英文languageUserDefinedArray[{key: StaticTextDefaultValue}]通过这里扩展语言,修改 language 值为扩展 key 即可,类型申明可手动导入toolbarsArray[all]选择性展示工具栏,可选内容如下[toolbars]prettierBooleantrue是否启用 prettier 优化 md 内容prettierCDNStringstandalone prettierMDCDNStringparser-markdowneditorNameString'editor'当在同一页面放置了多个编辑器,最好提供该属性以区别某些带有 ID 的内容

[toolbars]

[
  'bold',
  'underline',
  'italic',
  'strikeThrough',
  'title',
  'sub',
  'sup',
  'quote',
  'unorderedList',
  'orderedList',
  'codeRow',
  'code',
  'link',
  'image',
  'table',
  'revoke',
  'next',
  'save',
  'pageFullscreen',
  'fullscreen',
  'preview',
  'htmlPreview',
  'github'
];

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

[StaticTextDefaultValue]

export interface StaticTextDefaultValue {
  toolbarTips?: ToolbarTips;
  titleItem?: {
    h1?: string;
    h2?: string;
    h3?: string;
    h4?: string;
    h5?: string;
    h6?: string;
  };
  linkModalTips?: {
    title?: string;
    descLable?: string;
    descLablePlaceHolder?: string;
    urlLable?: string;
    UrlLablePlaceHolder?: string;
    buttonOK?: string;
    buttonUpload?: string;
  };
}
名称入参说明onChangev:String内容变化事件(当前与textareoninput事件绑定,每输入一个单字即会触发)onSavev:String保存事件,快捷键与保存按钮均会触发onUploadImgfiles:FileList, callback:Function上传图片事件,弹窗会等待上传结果,务必将上传后的 urls 作为 callback 入参回传

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

键位功能说明开发标记CTRL + S保存触发编辑器的onSave回调√CTRL + B加粗**加粗**√CTRL + U下划线<u>下划线</u>√CTRL + I斜体*斜体*√CTRL + 1-61-6 级标题# 标题√CTRL + ↑上角标<sup>上角标</sup>√CTRL + ↓下角标<sub>下角标</sub>√CTRL + Q引用> 引用√CTRL + O有序列表1. 有序列表√CTRL + L链接[链接](https://imbf.cc)√CTRL + T表格`\表格\` 放弃开发(无法实现)xCTRL + Z撤回触发编辑器内内容撤回,与系统无关√CTRL + SHIFT + S删除线~删除线~√CTRL + SHIFT + U无序列表- 无序列表√CTRL + SHIFT + C块级代码多行代码块√CTRL + SHIFT + I图片链接![图片](https://imbf.cc)√CTRL + SHIFT + Z前进一步触发编辑器内内容前进,与系统无关√CTRL + SHIFT + F美化内容 √CTRL + ALT + C行内代码行内代码块√
yarn add md-editor-v3

jsx 语法项目

import { defineComponent, reactive } from 'vue';
import Editor from 'md-editor-v3';
import 'md-editor-v3/lib/style.css';
import hljs from 'highlight.js';
import 'highlight.js/styles/atom-one-dark.css';

export default defineComponent({
  setup() {
    const md = reactive({
      text: 'default markdown content'
    });
    return () => (
      <Editor hljs={hljs} modelValue={md.text} onChange={(value) => (md.text = value)} />
    );
  }
});

vue 模板项目

<template>
  <editor v-model="text" pageFullScreen></editor>
</template>

<script>
import { defineComponent } from 'vue';
import Editor from 'md-editor-v3';
import 'md-editor-v3/lib/style.css';

export default defineComponent({
  name: 'VueTemplateDemo',
  components: { Editor },
  data() {
    return {
      text: '默认值'
    };
  }
});
</script>

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

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

async onUploadImg(files: FileList, callback: (urls: string[]) => void) {
  const res = await Promise.all(
    Array.from(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: any) => item.data.url));
}

该项目目前只生存了3周,使用中有bug期待你能留言给我,有想要的功能期待了解哦。另外审美一般,轻喷。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK