vue2.x 富文本组件 支持图片、文件、视频上传

<template>
  <div>
    <editor v-model="content" :init="init" :disabled="disabled"></editor>
  </div>
</template>

<script>
import tinymce from "tinymce/tinymce";
import Editor from "@tinymce/tinymce-vue";
import "tinymce/icons/default/icons";
import "tinymce/themes/silver";
import "tinymce/plugins/image";
// import "tinymce/plugins/media"; // 视频上传暂不处理
import "tinymce/plugins/table";
import "tinymce/plugins/lists";
import "tinymce/plugins/contextmenu";
import "tinymce/plugins/wordcount";
import "tinymce/plugins/colorpicker";
import "tinymce/plugins/textcolor";
import "tinymce/plugins/preview";
import "tinymce/plugins/code";
import "tinymce/plugins/link";
import "tinymce/plugins/advlist";
import "tinymce/plugins/codesample";
import "tinymce/plugins/hr";
import "tinymce/plugins/fullscreen";
import "tinymce/plugins/textpattern";
import "tinymce/plugins/searchreplace";
import "tinymce/plugins/autolink";
import "tinymce/plugins/directionality";
import "tinymce/plugins/visualblocks";
import "tinymce/plugins/visualchars";
import "tinymce/plugins/template";
import "tinymce/plugins/charmap";
import "tinymce/plugins/nonbreaking";
import "tinymce/plugins/insertdatetime";
import "tinymce/plugins/autosave";
import "tinymce/plugins/autoresize";
import {Loading} from 'element-ui';

export default {
  name: "tinymceEditor",
  components: {
    Editor
  },
  props: {
    value: {
      type: String,
      default: ""
    },
    disabled: {
      type: Boolean,
      default: false
    },
    plugins: {
      type: [String, Array],
      default:
          "preview searchreplace autolink directionality visualblocks visualchars fullscreen image link template code codesample table charmap hr nonbreaking insertdatetime advlist lists wordcount textpattern autosave autoresize"
    },
    toolbar: {
      type: [String, Array],
      default:
          "code undo redo restoredraft | cut copy paste pastetext | forecolor backcolor bold italic underline strikethrough link codesample | alignleft aligncenter alignright alignjustify outdent indent formatpainter | \
      styleselect formatselect fontselect fontsizeselect | bullist numlist | blockquote subscript superscript removeformat | \
      table image charmap hr pagebreak insertdatetime | fullscreen preview"
    }
  },
  data() {
    return {
      //初始化配置
      init: {
        menubar: false, // 顶部菜单栏显隐
        language_url: "./tinymce/langs/zh_CN.js",
        language: "zh_CN",
        skin_url: "./tinymce/skins/ui/oxide",
        height: 770,
        min_height: 770,
        max_height: 770,
        toolbar_mode: "wrap",
        plugins: this.plugins,
        toolbar: this.toolbar,
        content_style: "p {margin: 5px 0;}",
        fontsize_formats: "12px 14px 16px 18px 24px 36px 48px 56px 72px",
        font_formats:
            `微软雅黑=Microsoft YaHei,Helvetica Neue,PingFang SC,sans-serif;苹果苹方=PingFang SC,Microsoft YaHei,sans-serif;宋体=simsun,serif;仿宋体=FangSong,serif;黑体=SimHei,楷体=楷体;
            隶书=隶书;幼圆=幼圆;sans-serif;Andale Mono=andale mono,times;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;
            Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier;Georgia=georgia,palatino;Helvetica=helvetica;Impact=impact,chicago;Symbol=symbol;
            Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco;Times New Roman=times new roman,times;Trebuchet MS=trebuchet ms,geneva;Verdana=verdana,geneva;
            Webdings=webdings;Wingdings=wingdings,zapf dingbats`,
        branding: false,
        // 文件上传
        file_picker_callback: function (callback, value, meta) {
          const _this = this
          //文件分类
          let filetype = '.jpg, .jpeg, .png, .pdf, .txt, .zip, .rar, .7z, .doc, .docx, .xls, .xlsx, .ppt, .pptx, .mp3, .mp4';
          //为不同插件指定文件类型及后端地址
          switch (meta.filetype) {
            case 'image':
              filetype = '.jpg, .jpeg, .png';
              break;
            case 'media':
              filetype = '.mp3, .mp4';
              break;
            case 'file':
              filetype = '.pdf';
              break;
            default:
          }
          //后端接收上传文件的地址
          let uploadUrl = `${serverConfig.NEW_MEETING_RESERVATION_BACKEND}/api/oss`;
          //模拟出一个input用于添加本地文件
          const token = sessionStorage.getItem("Admin-Token") || sessionStorage.getItem("token")
          let input = document.createElement('input');
          input.setAttribute('type', 'file');
          input.setAttribute('accept', filetype);
          input.click();
          input.onchange = function () {
            //获取上传的文件
            const file = this.files[0];
            // 定义暂存上传文件的变量
            const maxSize = 15 * 1024 * 1024
            if (file.size > maxSize) {
              _this.$message.warn('上传文件的大小不能超过15M')
              return
            }
            const loading = Loading.service({
              lock: true,
              text: "Loading",
              spinner: "el-icon-loading",
              background: "rgba(0, 0, 0, 0.7)",
            });
            let xhr, formData;
            xhr = new XMLHttpRequest();
            xhr.withCredentials = false;
            xhr.open('POST', uploadUrl);
            xhr.setRequestHeader('X-Id-Token', token)
            xhr.onload = function () {
              loading.close();
              const json = JSON.parse(xhr.responseText);
              if (xhr.status != 200) {
                _this.$message.error(json.msg)
                return;
              }
              // Provide file and text for the link dialog
              if (meta.filetype === 'file') {
                //json.data.link为预览地址,此处需要下载地址
                const url = `${serverConfig.NEW_MEETING_RESERVATION_BACKEND}/api/oss/download/${json.data.id}?idToken=${token}`
                callback(url, {text: json.data.name});
              }
              // Provide image and alt text for the image dialog
              if (meta.filetype === 'image') {
                callback(json.data.link, {text: json.data.name});
              }
              // Provide alternative source and posted for the media dialog
              if (meta.filetype === 'media') {
                callback(json.data.link, {source2: '', poster: ''});
              }
              // callback(json.location);
              input.value = ''
            };
            formData = new FormData();
            formData.append('file', file, file.name);
            xhr.send(formData);
          }
        },
      },
      content: this.value,
    }
  },
  mounted() {
    tinymce.init({});
  },
  methods: {},
  watch: {
    value(newValue) {
      this.content = newValue;
    },
    content(newValue) {
      this.$emit("input", newValue);
    }
  }
}
</script>

<style scoped lang="scss">

</style>

效果图:

相关推荐
流云枫木几秒前
C++ STL常用查询手册
开发语言·c++
凡人的AI工具箱6 分钟前
15分钟学 Python 第38天 :Python 爬虫入门(四)
开发语言·人工智能·后端·爬虫·python
码农超哥同学16 分钟前
Python知识点:在Python编程中,如何使用Gensim进行主题建模
开发语言·python·面试·编程
奔跑吧邓邓子20 分钟前
JSON 全知全解:深入探索 JSON 的奥秘
开发语言·python·json
风清扬_jd40 分钟前
Chromium 硬件加速开关c++
java·前端·c++
陈序缘1 小时前
Go语言实现长连接并发框架 - 消息
linux·服务器·开发语言·后端·golang
Ambition_LAO1 小时前
不同版本的 Selenium 和 WebDriver 的 API 兼容性问题
开发语言·python
worxfr1 小时前
Python Selenium常用语法汇总(包含XPath语法)
开发语言·python·selenium·xpath
weixin_545032311 小时前
JavaScript代码如何测试?
开发语言·javascript·ecmascript
谢尔登2 小时前
【React】事件机制
前端·javascript·react.js