发布时间:2023-05-26 文章分类:WEB开发, 电脑百科 投稿人:赵颖 字号: 默认 | | 超大 打印

安装:

  1. 我用的是tinymce最新版本v6
npm install tinymce -S
npm install @tinymce/tinymce-vue -S

2.安装语言包:Language Packages | Trusted Rich Text Editor | TinyMCE

3.在项目public文件夹下--新建tinymce文件夹,安装包解压在该文件夹下

vue3 使用tinymce编辑器实现单/多图片上传,附件上传,视频上传

 封装组件TEditor.vue

<template>
  <editor v-model="myValue" :init="init"></editor>
</template>
<script setup lang="ts">
import { uploadImg } from "../api/module/new_news";
//JS部分
//在js中引入所需的主题和组件
import tinymce from "tinymce/tinymce";
import "tinymce/skins/content/default/content.css";
import Editor from "@tinymce/tinymce-vue";
import "tinymce/themes/silver";
import "tinymce/themes/silver/theme";
import "tinymce/icons/default"; //引入编辑器图标icon,不引入则不显示对应图标
import "tinymce/models/dom"; // 这里是个坑 一定要引入
//在TinyMce.vue中接着引入相关插件
import "tinymce/icons/default/icons";
import "tinymce/plugins/image"; // 插入上传图片插件
import "tinymce/plugins/media"; // 插入视频插件
import "tinymce/plugins/table"; // 插入表格插件
import "tinymce/plugins/lists"; // 列表插件
import "tinymce/plugins/wordcount"; // 字数统计插件
import "tinymce/plugins/code"; // 源码
import "tinymce/plugins/fullscreen"; //全屏
import "tinymce/plugins/preview"; //预览
// import 'tinymce/plugins/paste'; //粘贴插件
import "tinymce/plugins/pagebreak"; //插入分页符
import "tinymce/plugins/codesample";
import "tinymce/plugins/searchreplace";
import "tinymce/plugins/link";
import "tinymce/plugins/autosave";
import "tinymce/plugins/autolink";
import "tinymce/plugins/anchor";
import "/public/tinymce/plugins/axupimgs/plugin.js";
// /
// import "tinymce/plugins/fullpage";autolink anchor
//接下来定义编辑器所需要的插件数据
import { reactive, ref } from "vue";
import { onMounted, defineEmits, watch } from "vue";
// import axios from "axios";
import request from "@/utils/axios";
// import { updateImg } from "@/api/order/order";
const emits = defineEmits(["getContent"]);
//这里我选择将数据定义在props里面,方便在不同的页面也可以配置出不同的编辑器,当然也可以直接在组件中直接定义
const props = defineProps({
  value: {
    type: String,
    default: () => {
      return "";
    },
  },
  baseUrl: {
    type: String,
    default: "",
  },
  disabled: {
    type: Boolean,
    default: false,
  },
  plugins: {
    type: [String, Array],
    // default: "lists image media table wordcount fullscreen",
    default:
      " wordcount table searchreplace preview pagebreak  fullscreen  codesample  autosave autolink anchor  autolink image media lists  link code   image axupimgs",
  },
  toolbar: {
    type: [String, Array],
    default:
      "  fontsize fontfamily bold  italic lineheight underline alignleft aligncenter alignright alignjustify anchor | undo redo |  formatselect | forecolor backcolor | bullist numlist outdent indent | lists link  image axupimgs media  table  | removeformat | fullscreen|preview code  codesample|searchreplace   ",
  }, //必填
  objId:{
    type: Object,
    default: {},
  }
});
// watch(()=>props.objId,(id,old)=>{
//   console.log(id,'xinid')
//   id=newId
// })
console.log(props.objId.newId,'++++++++++++++')
//用于接收外部传递进来的富文本
const myValue = ref(props.value);
//定义一个对象 init初始化
const init = reactive({
  selector: "textarea",
  language_url: "/cms/tinymce/langs/zh_CN.js", // 语言包的路径,具体路径看自己的项目,文档后面附上中文js文件
  language: "zh_CN", //语言
  //自动聚焦
  auto_focus: true,
  skin_url: "tinymce/skins/ui/oxide", // skin路径,具体路径看自己的项目
  height: 800, //编辑器高度
  width: "100%",
  branding: false, //是否禁用“Powered by TinyMCE”
  menubar: false, //顶部菜单栏显示
  image_dimensions: false, //去除宽高属性
  plugins: props.plugins, //这里的数据是在props里面就定义好了的
  toolbar: props.toolbar, //这里的数据是在props里面就定义好了的
  images_upload_url: "/news/picUpload",
  //  paste_convert_word_fake_lists: true, // 插入word文档需要该属性
  font_size_formats: "12px 14px 16px 18px 24px 36px 48px 56px 72px",
  font_family_formats:
    "微软雅黑=Microsoft YaHei,Helvetica Neue,PingFang SC,sans-serif;苹果苹方=PingFang SC,Microsoft YaHei,sans-serif;宋体=simsun,serif",
  line_height_formats: "1 1.2 1.4 1.6 2",
  paste_webkit_styles: "all",
  paste_merge_formats: true,
  nonbreaking_force_tab: false,
  paste_auto_cleanup_on_paste: false,
  file_picker_types: "file image media",
  content_css: "tinymce/skins/content/default/content.css", //以css文件方式自定义可编辑区域的css样式,css文件需自己创建并引入
  // 文件上传
  file_picker_callback: (callback, value, meta) => {
    //,,m4v,avi,wmv,rmvb,mov,mpg,mpeg,webm
    let filetype =
      ".pdf, .txt, .zip, .rar, .7z, .doc, .docx, .xls, .xlsx, .ppt, .pptx, .mp3, .mp4,.mkv, .avi,.wmv, .rmvb,.mov,.mpg,.mpeg,.webm, .jpg, .jpeg, .png, .gif"; //限制文件的上传类型
    let inputElem = document.createElement("input"); //创建文件选择
    inputElem.setAttribute("type", "file");
    inputElem.setAttribute("accept", filetype);
    inputElem.click();
    inputElem.onchange = () => {
      let upurl = "";
      let file = inputElem.files[0]; //获取文件信息
      const ph = import.meta.env.VITE_APP_IMAGE_URL;
      let params = new FormData();
      if (file.type.slice(0, 5) == "video") {
        //判断文件类型
        upurl = "/news/videoUpload";
        params.append("file", file);
        params.append("id", props.objId.newId);
      } else if (file.type.slice(0, 5) == "image") {
        upurl = "/news/picUpload";
        params.append("file", file);
        params.append("id", props.objId.newId);
      } else {
        upurl = "/news/attachUpload";
        params.append("file", file);
        params.append("siteId", props.objId.siteId);
        params.append("newsId", props.objId.newId);
        params.append("attachDesc", "");
      }
      if (file.type.slice(0, 5) == "image" && file.size / 1024 / 1024 > 2) {
        alert("上传失败,图片大小请控制在2M以内");
      } else if (
        file.type.slice(0, 5) == "video" &&
        file.size / 1024 / 1024 > 500
      ) {
        alert("上传失败,视频大小请控制在 500M 以内");
      } else if (file.size / 1024 / 1024 > 10) {
        alert("上传失败,文件大小请控制在 10M 以内");
      } else {
        let config = {
          headers: {
            "Content-Type": "multipart/form-data",
          },
        };
        request
          .post(upurl, params, config)
          .then((res) => {
            if (res.code == 200) {
              if (res.data.url) {
                callback(ph + res.data.url, {
                  text: res.data.alt,
                  title: res.data.name,
                });
              } else {
                console.log(res);
                //上传成功,在回调函数里填入文件路径
                callback(ph + res.data);
              }
            } else {
              alert("上传失败");
            }
          })
          .catch(() => {
            alert("上传出错,服务器开小差了呢");
          });
      }
    };
  },
});
//监听外部传递进来的的数据变化
watch(
  () => props.value,
  () => {
    myValue.value = props.value;
    emits("getContent", myValue.value);
  }
);
//监听富文本中的数据变化
watch(
  () => myValue.value,
  () => {
    emits("getContent", myValue.value);
  }
);
//在onMounted中初始化编辑器
onMounted(() => {
  tinymce.init({});
});
</script>

 上传图片vue3 使用tinymce编辑器实现单/多图片上传,附件上传,视频上传

 上传附件vue3 使用tinymce编辑器实现单/多图片上传,附件上传,视频上传

 上传视频vue3 使用tinymce编辑器实现单/多图片上传,附件上传,视频上传

 最终效果如下图vue3 使用tinymce编辑器实现单/多图片上传,附件上传,视频上传

批量上传图片实现

需要安装插件ax多图片批量上传插件 | TinyMCE中文文档中文手册vue3 使用tinymce编辑器实现单/多图片上传,附件上传,视频上传

 注意:安装完以后放到最开始新建的tinymce文件夹下

vue3 使用tinymce编辑器实现单/多图片上传,附件上传,视频上传

 但是在文件里引入的时候会有问题vue3 使用tinymce编辑器实现单/多图片上传,附件上传,视频上传

 这里借鉴了在vuecli3.0+中使用tinymce及实现多图上传,文件上传,公式编辑等功能 - huihuihero - 博客园

为什么引入的是plugin.js是因为axupimgs中没有index.js文件,我试了一下写一个index.js 引入的时候还是会报错,具体的原因我也不大明白,(就是菜)..

不报错的引入方式,但是会有下面的提示要使用/tinymce/plugins/axupimgs/plugin.js这种方式,但是按照这个来就会报错vue3 使用tinymce编辑器实现单/多图片上传,附件上传,视频上传

vue3 使用tinymce编辑器实现单/多图片上传,附件上传,视频上传

引入完以后最重要的就是去plugin.js文件修改一下路径哦!!!不然就会出现空白的情况

就是你们项目的地址

 vue3 使用tinymce编辑器实现单/多图片上传,附件上传,视频上传

 插件安装好修改完以后其他的就很好实现了,直接看代码吧vue3 使用tinymce编辑器实现单/多图片上传,附件上传,视频上传

多个图片上传主要是基于单个图片上传的,所以方法都是一样的,这里最重要的就是单张图片和多个图片回调传的参数不一样. 

最后看一下效果吧!vue3 使用tinymce编辑器实现单/多图片上传,附件上传,视频上传

 vue3 使用tinymce编辑器实现单/多图片上传,附件上传,视频上传

我也是第一次用这个编辑器,写的不好的地方,大佬们多指正