vue3中通过vditor插件实现自定义上传图片、录入echarts、脑图、markdown语法的编辑器

news2024/12/29 11:10:30

1、下载Vditor插件

npm i vditor

我的vditor版本是3.10.2,大家可以自行选择下载最新版本

官网:Vditor 一款浏览器端的 Markdown 编辑器,支持所见即所得(富文本)、即时渲染(类似 Typora)和分屏 - 链滴

示例:

Vditor 示例 - 链滴

2、引入vue文件

import Vditor from "vditor";
import "vditor/dist/index.css";

 3、封装vditor自定义组件

<template>
  <div>
    <div
      :id="vidtorId"
      class="vditor"
      :class="{ 'vditor-hidden': showPreview }"
    ></div>
  </div>
</template>
<script setup>
import Vditor from "vditor";
import "vditor/dist/index.css";
import { getToken } from "@/utils/auth";
const { proxy } = getCurrentInstance();
const props = defineProps({
  height: {
    type: [Number, String],
    default: "inherit",
  },
  modelValue: {
    type: String,
    default: "",
  },
  knwlgId: {
    type: String,
    default: "",
  },
  showPreview: {
    type: Boolean,
    default: false,
  },
  disabled: {
    type: Boolean,
    default: false,
  },
  // 额外的formData参数
  extraData: {
    type: Object,
    default: () => ({}),
  },
  uploadURL: {
    type: String,
    default: "",
  },
  previewURL: {
    type: String,
    default: "/ekms/images/v1/preview/",
  },
  placeholder: {
    type: String,
    default: "",
  },
});

const vidtorId = ref(
  "vidtor-" + +new Date() + ((Math.random() * 1000).toFixed(0) + "")
);

// 图片上传地址判断,这里大家可以根据自己需求写死或通过props传入
const imgUploadUrl = computed(() => {
  return !props.uploadURL
    ? `/ekms/images/v1/upload?knwlgId=${props.knwlgId}`
    : props.uploadURL;
});

watch(
  () => props.showPreview,
  (newValue, oldValue) => {
    let previewDom =
      contentEditor.value.vditor.toolbar.elements.preview.firstChild;
    let isPreview = previewDom.className.indexOf("vditor-menu--current") > -1;
    emits("update:showPreview", isPreview ? false : true);
    previewDom.click();
  }
);

const emits = defineEmits([
  "update:modelValue",
  "update:showPreview",
  "setHtml",
]);
const contentEditor = ref(null);

onMounted(() => {
  contentEditor.value = new Vditor(vidtorId.value, {
    height: props.height,
    mode: "wysiwyg", //所见即所得(wysiwyg)、即时渲染(ir)、分屏预览(sv)
    value: props.modelValue,
    cdn: import.meta.env.VITE_APP_VDITOR_API,
    placeholder: props.placeholder,
    toolbarConfig: {
      pin: true,
      // hide: true,
    },
    // outline: {
    //   enable: true, //展示大纲,position默认left
    // },
    cache: {
      enable: false, // 是否使用 localStorage 进行缓存
    },
    preview: {
      mode: "both", //显示模式
      delay: 10,
      actions: [],
      theme: {
        path: `${import.meta.env.VITE_APP_VDITOR_API}/dist/css/content-theme`,
      },
    },
    toolbar: [
      "emoji",
      "headings",
      "bold",
      "italic",
      "strike",
      "link",
      "|",
      "list",
      "ordered-list",
      "check",
      "outdent",
      "indent",
      "|",
      "quote",
      "line",
      "code",
      "inline-code",
      "insert-before",
      "insert-after",
      "|",
      {
        //自定义上传
        hotkey: "",
        name: "upload",
        tip: "上传图片",
        className: "right",
      },

      "table",
      "|",
      "undo",
      "redo",
      "|",
      "code-theme",
      "content-theme",
      "preview",
       // 自定义清空内容的菜单
      {
        hotkey: "⇧⌘S",
        name: "clearAll",
        tipPosition: "n",
        tip: "清空内容",
        className: "right",
        icon: '<svg t="1696926237451" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2371" width="180" height="180"><path d="M512 838.858c10.89 0 19.732-9.158 19.732-20.43v-490.275c0-11.273-8.842-20.43-19.732-20.43s-19.755 9.157-19.755 20.43v490.275c0 11.272 8.842 20.43 19.755 20.43M629.877 838.813c10.935 0.428 20.138-8.37 20.475-19.688l28.665-489.69c0.427-11.272-8.077-20.745-18.99-21.195-10.935-0.405-20.137 8.415-20.475 19.688l-28.665 489.713c-0.405 11.317 8.1 20.767 18.99 21.172M848.038 185.142h-197.708v-81.653c0-22.545-17.685-40.882-39.51-40.882h-197.64c-21.87 0-39.532 18.338-39.532 40.882v81.653h-197.685c-10.913 0-19.755 9.158-19.755 20.475 0 11.272 8.843 20.407 19.755 20.407h39.577l39.488 653.67c6.367 44.73 35.415 81.72 79.065 81.72h355.793c43.65 0 71.573-37.44 79.088-81.72l39.488-653.67h39.578c10.867 0 19.755-9.135 19.755-20.408 0-11.317-8.888-20.475-19.755-20.475M413.157 103.49h197.64v81.653h-197.64v-81.653zM729.418 879.695c-2.655 21.555-17.73 40.86-39.533 40.86h-355.793c-21.87 0-36.54-19.057-39.532-40.86l-39.532-653.67h513.945l-39.555 653.67zM394.145 838.858c10.89-0.473 19.373-9.9 18.99-21.195l-29.070-489.712c-0.427-11.273-9.585-20.070-20.475-19.665-10.913 0.428-19.463 9.9-19.013 21.173l29.093 489.712c0.36 11.295 9.54 20.070 20.475 19.688z" p-id="2372"></path></svg>',
        click() {
          contentEditor.value.setValue("");
        },
      },
    ],
    // vditor结构渲染完成后
    after: () => {
      emits("setHtml", getValue(), getHTML());
      // 这里根据传入的disabled来设置vditor是否可输入内容
      props.disabled && contentEditor.value.disabled();
    },
    input: () => {
      // 变更事件回调
      emits("setHtml", getValue(), getHTML());
    },
    // 上传图片
    upload: {
      accept: "image/*", // 图片类型
      fieldName: "file",
      url: import.meta.env.VITE_APP_BASE_API + imgUploadUrl.value, // 图片上传的接口路径
      extraData: props.extraData, // 要携带的额外的formData参数
      headers: {
        Authorization: "Bearer " + getToken(), // 用户身份信息
      },
      filename(name) {  // 过滤特殊字符
        return name
          .replace(/[^(a-zA-Z0-9\u4e00-\u9fa5\.)]/g, "")
          .replace(/[\?\\/:|<>\*\[\]\(\)\$%\{\}@~]/g, "")
          .replace("/\\s/g", "");
      },
      // 粘贴图片的情况下上传的接口路径
      linkToImgUrl: import.meta.env.VITE_APP_BASE_API + imgUploadUrl.value,
      max: 20 * 1024 * 1024,
      multiple: false,
      withCredentials: false,
      // 图片上传校验,可以校验图片大小及类型
      validate(files) {
        const isLt2M = files[0].size / 1024 / 1024 < 20;
        if (!isLt2M) {
          proxy.$modal.msgError("上传图片大小不能超过 20MB!");
        }
        if (!files[0].type.includes("image")) {
          return proxy.$modal.msgError("仅支持上传图片!");
        }
      },
      //粘贴图片回显处理,如果有图片加了防盗链,则让后台代理替换成自己的图片
      linkToImgFormat(responseText) {
        let res = JSON.parse(responseText);
        if (!res.data?.imgId) return;
        let end = JSON.stringify({
          msg: "",
          code: 0,
          data: {
            originalURL:
              import.meta.env.VITE_APP_BASE_API +
              props.previewURL +
              res.data?.imgId, //图片原始地址记录到本地文件中,可以防止跨站点调用。
            url:
              import.meta.env.VITE_APP_BASE_API +
              props.previewURL +
              res.data?.imgId, //图片链接记录到本地文件中,可以防止跨站点调用。
          },
        });
        return end;
      },
      format(files, responseText) {
        var res = JSON.parse(responseText);
        if (!res.data?.imgId) return;
        //图片回显
        nextTick(() => {
          emits("setHtml", getValue(), getHTML());
        });
        return JSON.stringify({
          msg: "",
          code: 0,
          data: {
            errFiles: [],
            succMap: {
              [res.data.imgPath]:
                import.meta.env.VITE_APP_BASE_API +
                props.previewURL +
                res.data?.imgId,
            },
          },
        });
      },
    },
  });
});

function getValue() {
  return contentEditor.value.getValue(); //获取 Markdown 内容
}

// 获取html结构
function getHTML() {
  let dom = document.querySelector(
    ".vditor-content .vditor-wysiwyg .vditor-reset"
  )?.innerHTML;
  return dom;
}

function setValue(value) {
  return contentEditor.value.setValue(value); //设置 Markdown 内容
}

defineExpose({
  getHTML,
  setValue,
});
</script>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1864810.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

RT-Thread Studio实现静态线程

1创建项目 &#xff08;STM32F03ZET6&#xff09; RT-Thread项目与RT-Thread Nano 项目区别 RT-Thread: 完整版&#xff1a;这是RT-Thread的完整形态&#xff0c;适用于资源较丰富的物联网设备。功能&#xff1a;它提供了全面的中间件组件&#xff0c;如文件系统、网络协议栈、…

MS31011低压 5V DC 电机驱动

MS31011 是一款低压 5V 直流电机驱动芯片&#xff0c;为摄像机、消 费类产品、玩具和其他低压或者电池供电的运动控制类应用提 供了集成的电机驱动解决方案。 MS31011 能提供高达 0.8A 的输出电流。可以工作在 2.0~5.5V 的电源电压上。 MS31011 具有 PWM &#x…

比特币生态系统的现状与流动性提升的新路径

自2009年中本聪发布比特币白皮书以来&#xff0c;比特币一直被誉为“数字黄金”&#xff0c;在加密货币领域占据着不可动摇的地位。其去中心化、稀缺性和安全性&#xff0c;增强了其作为长期价值储存工具的吸引力。 相比之下&#xff0c;以太坊自2015年问世以来&#xff0c;凭…

oceanbase数据库安装和连接实战(阿里云服务器操作)

本文主要是安装oceanbase的单机版进行数据库的基础使用&#xff0c;oceanbase的数据库是兼容mysql数据库的&#xff0c;实际的兼容程度需要更深度的测试&#xff0c;本文主要是安装oceanbase并使用SQLynx的mysql驱动连接使用oceanbase数据库。 目录 1. 基础介绍 2. 安装说明 …

CentOS 7.9下安装配置Java环境

1.下载java安装包 下载java安装包 我已经给大家准备好了&#xff0c;下载连接 https://pan.baidu.com/s/1GK_juIc5rch0Kc4-EbxNNQ 提取码: 0124 2.创建目录 mkdir /usr/local/soft 3.解压压缩包到安装目录 tar xf jdk-8u401-linux-x64.tar.gz -C /usr/local/soft/ 4.配置环…

Strava VS Keep竞品分析

Strava VS Keep竞品分析 一、背景&#xff1a; 随着国民对身体健康的重视程度逐步增加&#xff0c;跑步、游泳、骑行在国内逐渐流行&#xff0c;人们都加入运动行列。随之不可缺少的则是对运动数据的记录&#xff0c;市面上针对此需求的app层出不穷&#xff0c;日活最多的5款…

成都爱尔巫雷院长提醒老花眼减轻了?可能患上白内障要注意!

到年龄不可避免的身体老化&#xff0c;眼睛也是其中之一&#xff0c;40、50岁时眼睛因为老化可能出现老花问题&#xff0c;如果本就有近视、散光&#xff0c;老花加重更是“雪上加霜”。 当某一天老花症状减轻&#xff0c;别顾着高兴&#xff0c;反而应引起重视&#xff0c;这…

IMX6ULL SD卡启动uboot+kernel+rootfs

目录 1. 背景说明 2.SD卡启动 2.1准备条件 2.2 对SD卡分区格式化 2.3 制作sd卡镜像 3.效果测试 1. 背景说明 网络上绝大数教程&#xff0c;教大家把uboot烧录到SD卡&#xff0c;然后uboot启动后&#xff0c;通过TFTP下载kernel和设备树&#xff0c;然后通过nfs挂载文件系…

Hi3861 OpenHarmony嵌入式应用入门--LiteOS semaphore作为锁

CMSIS 2.0 接口中的 Semaphore&#xff08;信号量&#xff09;是用于嵌入式系统中多线程或中断服务例程&#xff08;ISR&#xff09;之间同步和共享资源保护的重要机制。Semaphore 是一种用于控制对多个共享资源访问的同步机制。它可以被看作是一个计数器&#xff0c;用于跟踪可…

采购OLED透明屏指南

一、引言 OLED透明屏作为一种前沿的显示技术&#xff0c;以其独特的透明度和出色的显示效果&#xff0c;受到了众多行业的青睐。在采购OLED透明屏时&#xff0c;需要综合考虑多个因素&#xff0c;以确保选择到符合需求的高质量产品。以下是一份详细的采购OLED透明屏指南&#x…

智领全栈,模力全开|2024中国智算中心全栈技术大会,锐捷网络引爆智算网络新风潮

6月25日至27日&#xff0c;2024中国智算中心全栈技术大会暨展览会、第5届中国数据中心绿色能源大会暨第10届中国(上海)国际数据中心产业展览会在上海新国际博览中心隆重开幕。此次大会由CDCC和益企研究院主办&#xff0c;以“AI赋能&#xff0c;重构未来”为主题&#xff0c;吸…

kettle 安装9.0版本 建议设置为英语

0.新建转换的常用组件 0. Generate rows 定一个字符串 name value就是字符串的值 0.1 String operations 字段转大写 去空格 1. Json input 来源于一个json文件 1.json 或mq接收到的data内容是json字符串 2. Json output 定义Jsonbloc值为 data, 左侧Fieldname是数据库查…

镜头下的光学

说实话&#xff0c;当我看到几何光学的内容全是初中的解析几何的时候&#xff0c;我就觉得讲的方式太原始了&#xff0c;而且太过复杂也看不懂。所以我尝试做了数学建模&#xff0c;发现建模之后模型可以解释一些物理现象&#xff0c;也不会有矛盾的地方&#xff0c;那就算过得…

软件测试学习笔记丨JUnit5执行顺序

本文转自测试人社区&#xff0c;原文链接&#xff1a; https://ceshiren.com/t/topic/28025 指定顺序使用场景 测试用例有业务逻辑相关集成测试(主流程测试) 排序方式 方法排序类排序Suite官方网站没有明确说明默认排序的具体规则 方法排序的类型 方法排序-Order 注解指定排序 …

2024最新three.js在vue中的使用(保姆级手把手教程)

2024最新three.js在vue中的使用&#xff08;保姆级手把手教程&#xff09; 一、three.js介绍 Three.js 是一个跨浏览器的脚本&#xff0c;使用 JavaScript 函数库或 API 来在网页浏览器中创建和展示动画的 三维计算机图形。写这篇文章也是因为目前越来越多的3dweb出现&#x…

数据模拟接口

因项目需要&#xff0c;使用FastAPI框架编写了一个简单的HTTP API服务&#xff0c;用于生成短信发送记录和短信回复记录。 is_valid_phone_numbers函数用于验证手机号码列表的格式是否正确。current_time_str函数返回当前时间的字符串表示&#xff0c;可选参数format用于指定时…

聚乙烯醇(PVA)涂布型薄膜是高阻隔性包装材料 我国市场增长快速

聚乙烯醇&#xff08;PVA&#xff09;涂布型薄膜是高阻隔性包装材料 我国市场增长快速 聚乙烯醇&#xff08;PVA&#xff09;涂布型薄膜&#xff0c;是以其他塑料薄膜&#xff08;主要是双向拉伸薄膜&#xff09;为基材&#xff0c;以聚乙烯醇为涂料&#xff0c;经表面涂布后制…

推荐5个国内宝藏级物联网平台

随着物联网技术的快速发展物联网平台正成为企业和个人开发者构建智能系统的首选。这些平台以其灵活性、成本效益和强大的社区支持&#xff0c;为用户提供了快速开发和部署物联网解决方案的新途径。本文将介绍几款市场上流行的物联网平台&#xff0c;以及它们各自的技术优势和核…

昇思25天学习打卡营第1天|基本介绍与快速入门

先贴上打卡截图 基本介绍 首先来看基本介绍&#xff0c;昇思MindSpore是华为的一个全场景深度学习框架&#xff0c;属于昇腾AI全栈的一部分。 总体架构如下图所示&#xff08;来自官方学习材料&#xff09; 从对底层多样性硬件适用的Runtime到应用层面的Model Zoo、科学计算…

Windows bat 提取多个目录下的文件,到一个目录

批处理命令 echo off setlocalrem 设置源目录和目标目录 set "sourceDirE:\motrix" set "targetDirE:\新建文件夹"rem 创建目标目录&#xff0c;如果不存在 if not exist "%targetDir%" mkdir "%targetDir%"rem 循环遍历源目录中的所…