vue3+tinymce 富文本指定上传图片宽度并压缩

初始化:     

  1. npm install npm install tinymce -S

  2. npm install @tinymce/tinymce-vue -S

  3. 下载完依赖包后,我们在根目录的public文件夹种新建 tinymce文件夹存放文件。在tinymce中新建langs文件夹把下载好的中文js文件放入,此处为中文语言包或者富文本皮肤

  4.  TinyMCE中文文档中文手册

  5. 中文语言包下载 Language Packages | Trusted Rich Text Editor | TinyMCE

  6.  tinymce 插件使用可以下载至本地文件夹放入node_modules中

      7. 直接粘贴第三方网站内容,让图片自动存入自己的服务器,具体代码参考注释部分;从word,text等文件中直接粘贴图片,存入本地,和后端已商议存储方式,由于领导认为无需如此操作,后续工作未完成;有解决方案的朋友可以私信我

<template>

  <!-- 富文本 -->

  <div>

    <editor style="z-index: 5000" class="el-textarea__inner" v-model="content" :init="init"></editor>

  </div>

</template>

这里需要注意 tinymce-vue 和tinymce的版本,高版本的tinymce不兼容

"@tinymce/tinymce-vue": "^5.1.1","tinymce": "^5.10.9","vue": "^3.4.21"。

<script setup>

//引入tinymce编辑器

import Editor from "@tinymce/tinymce-vue";



//引入方式引入node_modules里的tinymce相关文件文件

import tinymce from "tinymce/tinymce"; //tinymce默认hidden,不引入则不显示编辑器

import "tinymce/themes/silver"; //编辑器主题,不引入则报错

import "tinymce/icons/default"; //引入编辑器图标icon,不引入则不显示对应图标



// 引入编辑器插件

import "tinymce/plugins/advlist"; //高级列表

import "tinymce/plugins/autolink"; //自动链接

import "tinymce/plugins/autosave"; //自动存稿

import "tinymce/plugins/charmap"; //特殊字符

import "tinymce/plugins/code"; //编辑源码

import "tinymce/plugins/codesample"; //代码示例

import "tinymce/plugins/directionality"; //文字方向

import "tinymce/plugins/emoticons"; //表情

import "tinymce/plugins/fullscreen"; //全屏

import "tinymce/plugins/help"; //帮助

import "tinymce/plugins/image"; //插入编辑图片

import "tinymce/plugins/importcss"; //引入css

import "tinymce/plugins/insertdatetime"; //插入日期时间

import "tinymce/plugins/link"; //超链接

import "tinymce/plugins/lists"; //列表插件

import "tinymce/plugins/media"; //插入编辑媒体

import "tinymce/plugins/nonbreaking"; //插入不间断空格

import "tinymce/plugins/pagebreak"; //插入分页符

import "tinymce/plugins/preview"; //预览

import "tinymce/plugins/save"; //保存

import "tinymce/plugins/searchreplace"; //查找替换

import "tinymce/plugins/table"; //表格

import "tinymce/plugins/template"; //内容模板

import "tinymce/plugins/visualchars"; //显示不可见字符

import "tinymce/plugins/wordcount"; //字数统计

import "tinymce/plugins/paste"; //粘贴复制

import "tinymce/plugins/letterspacing"; //字间距,此插件为非集成插件需要下载至本地




import { onMounted } from "vue";

import {compress, compressAccurately,imagetoCanvas,dataURLtoFile} from 'image-conversion';




const action = ref('/api/File/UploadFile')

const imgUrl = ref(import.meta.env.VITE_APP_BASE_API)

import { copyUploadImg,fileUrlConvert } from "@/api/file";



const content = defineModel('content')

const props =  defineProps({
   showImageVideo:{
      type: [Boolean, String],
      default:true
   },     
 })



  let plug = "preview searchreplace autolink directionality visualchars fullscreen link template paste letterspacing code codesample table charmap  pagebreak nonbreaking insertdatetime advlist lists wordcount autosave "



  let bar = "fullscreen undo redo restoredraft | cut copy pastetext | forecolor backcolor bold italic underline strikethrough link | alignleft aligncenter alignright alignjustify outdent indent | \

                  styleselect formatselect fontselect fontsizeselect | bullist numlist | blockquote subscript superscript removeformat | \

                  table charmap emoticons pagebreak insertdatetime  preview | code selectall | indent2em lineheight letterspacing formatpainter axupimgs paste "

  let barImg = "image  media "



  const plugins = ref(props.showImageVideo? plug+barImg : plug)

  const toolbar = ref(props.showImageVideo? bar+barImg : bar)

  const newImgUrl = ref([])

  const init = ref({

        language_url: import.meta.env.VITE_BASE_URL+'tinymce/langs/zh_CN.js', //引入语言包文件

        language: "zh_CN",

        skin_url: import.meta.env.VITE_BASE_URL+ 'tinymce/skins/ui/oxide', //皮肤:浅色

        content_css:import.meta.env.VITE_BASE_URL + "tinymce/skins/content/default/content.css",

        min_height: 350,

        max_height: 770,

        toolbar_mode: "wrap",

        plugins: plugins,

        toolbar: 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;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;",

        branding: false,

        paste_webkit_styles:"all",

        paste_data_images: false,

        paste_as_text: props.showImageVideo? false : true,

        promotion: false,

        images_upload_handler: async function (blobInfo, succFun, failFun) {

          console.log('上传数据',blobInfo,blobInfo.blob())

          let fileBlob = blobInfo.blob()  

          const comSize = Math.ceil(fileBlob.size/1024) > 500? 500 : Math.ceil(fileBlob.size/1024)

          console.log('fileName',fileBlob.name,fileBlob.size)

          const img = new Image();  

          img.src =  blobInfo.blobUri();

          img.onload=function(){

            console.log('img',img.width,img.height,Math.ceil(750*img.height/img.width))

            // 配置绘制选项

            const options = {

                width: 750, // 设置目标宽度为800px

                height:Math.ceil(750*img.height/img.width),

                quality: 0.8,

            };

            // 开始绘制

            imagetoCanvas(img, options)

            .then((canvas) => {

              canvas.toBlob((blob)=>{

                //开始压缩

                compressAccurately(blob,comSize).then((blob)=>{

                  const file = new File([blob], fileBlob.name, { type: fileBlob.type });  

                  console.log('file',file)

                  let formData = new FormData();

                  formData.append("formFile", file);

                  copyUploadImg(formData).then(res=>{

                    let location = imgUrl.value + res.altertiveFilePath;

                    succFun(location);

                  }).catch()

                }).catch((error)=>{})

              })

            })

            .catch((error) => {

                console.error('绘制失败', error)

            });

          }  
         
        },

        // paste_preprocess: async function(plugin, args) {

        //   const images = args.content.match(/<img[^>]+/g);

        //   console.log('所有的img标签:', images);

        //   if (images) {

        //     args.content = images.forEach((item) => {

        //       const srcMatch = item.match(/src="([^"]+)"/);

        //       console.log('上传地址',srcMatch)

        //       if (srcMatch) {

        //         const src = srcMatch[1];

        //         let params = {

        //           'fileUrlList':[src]

        //         }

        //         fileUrlConvert(params).then((res)=>{

        //           console.log('返回的路径',res[0].convertUrl)

        //           const newSrc = imgUrl.value+ res[0].originalUrl;

        //           item = item.replace(/src="([^"]+)"/g, `src="${newSrc}"`); // 替换图片链接

        //           return item;

        //         }).catch()   

        //       }

        //     });

        //   }

        // },


        // init_instance_callback: (editor) => {

        // // 粘贴远程图片本地化

        // editor.on('paste', (e) => {

        //   let remoteImages = [];

        //   const doc = editor.getDoc();

        //   const imgTags = doc.getElementsByTagName('img');



        //   if(imgTags.length) {

        //       for (let img of imgTags) {

        //           var src = img.getAttribute('_src') || img.src || '';

        //           if (/^(https?|ftp):/img.test(src) && !test(src)) {

        //               remoteImages.push(src);

        //           }

        //       }

        //   }

        //   console.log('remoteImages',remoteImages)

        //   if (remoteImages.length) {

        //       // 需要上传的图片

        //       fileUrlConvert({'fileUrlList':remoteImages}).then((data)=>{

        //         console.log('返回路径',data)

        //         let i, o, item, res, _src, __src, list = data;

        //         for (i = 0; item = imgTags[i++];) {

        //             _src = item.getAttribute('_src') || item.src || '';

        //             for (o = 0; res = list[o++];) {

        //                 if (_src == res.originalUrl && res.convertUrl) {// 抓取失败时不做替换处理

        //                     __src = res.url;

        //                     replaceImage(item, res); // 使用下面的新方法

        //                     const replaceImage = (image = item, data = res) => {

        //                         let src = editor.convertURL(data.url, 'src');

        //                         let attr = {

        //                             'src': data.url,

        //                             'data-app': data.app,

        //                             'data-aid': data.aid

        //                         };

        //                         if(data.db) {

        //                             attr['data-db'] = data.db;

        //                         } else {

        //                             attr['data-width'] = data.width;

        //                             attr['data-height'] = data.height;

        //                         }

        //                         replaceUrlInUndoStack(image.src, data.url);

        //                         editor.$(image).attr(attr).removeAttr('alt').removeAttr('data-mce-src');

        //                       }

        //                     break;

        //                 }

        //             }

        //         }

        //         // 同步到textarea

        //         editor.save();

        //       }).catch()

        //     }

        //   })

        // }

      })



  // // 设置白名单域名

  // const localDomains = ['cfyun.cc', 'cfyun.top'];



  // // 检测是否需要上传

  // const test = function test(url) {

  //     if (url.indexOf(location.host) !== -1 || /(^\.)|(^\/)/.test(url)) {

  //         return !0;

  //     }

  //     // 白名单

  //     if (localDomains) {

  //         for (let domain in localDomains) {

  //             if (localDomains.hasOwnProperty(domain) && url.indexOf(localDomains[domain]) !== -1) {

  //                 return !0;

  //             }

  //         }

  //     }

  //     return !1;

  // }




  // const each = function (xs, f) {

  //     for (var i = 0, len = xs.length; i < len; i++) {

  //         var x = xs[i];

  //         f(x, i);

  //     }

  // };

  // const map = function (xs, f) {

  //     var len = xs.length;

  //     var r = new Array(len);

  //     for (var i = 0; i < len; i++) {

  //         var x = xs[i];

  //         r[i] = f(x, i);

  //     }

  //     return r;

  // };



  // const replaceString = function (content, search, replace) {

  //     let index = 0;

  //     do {

  //         index = content.indexOf(search, index);

  //         if (index !== -1) {

  //             content = content.substring(0, index) + replace + content.substr(index + search.length);

  //             index += replace.length - search.length + 1;

  //         }

  //     } while (index !== -1);

  //     return content;

  // };



  // const replaceImageUrl = function (content, targetUrl, replacementUrl) {

  //   let replacementString = 'src="' + replacementUrl + '"' + (replacementUrl === 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7' ? ' data-placeholder="1"' : '');

  //   content = replaceString(content, 'src="' + targetUrl + '"', replacementString);

  //   return content;

  // };



  // const replaceUrlInUndoStack = function (targetUrl, replacementUrl) {

  //   each(editor.undoManager.data, function (level) {

  //       if (level.type === 'fragmented') {

  //           level.fragments = map(level.fragments, function (fragment) {

  //               return replaceImageUrl(fragment, targetUrl, replacementUrl);

  //           });

  //       } else {

  //           level.content = replaceImageUrl(level.content, targetUrl, replacementUrl);

  //       }

  //   });

  // };


</script>

  • 18
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue3中使用Tinymce实现单图上传的方法如下: 首先,你需要在Vue组件中引入Tinymce编辑器,并在data中定义一个变量来存储上传后的图片地址。 ```javascript <template> <div> <tinymce v-model="content" :init="tinymceConfig"></tinymce> </div> </template> <script> import { ref } from 'vue'; import tinymce from 'tinymce/tinymce'; import 'tinymce/icons/default'; import 'tinymce/themes/silver'; import 'tinymce/plugins/image'; import 'tinymce/plugins/link'; export default { components: { tinymce, }, data() { return { content: '', tinymceConfig: { plugins: 'image link', toolbar: 'image link', images_upload_handler: (blobInfo, success, failure) => { // 在这里进行图片上传的逻辑处理 // 你可以使用阿里云oss或其他方式进行图片上传 // 上传成功后,将图片地址返回给success函数 // 上传失败时,调用failure函数并传递错误信息 }, }, }; }, }; </script> ``` 在`images_upload_handler`函数中,你可以根据你的需求选择合适的图片上传方式。你可以使用阿里云oss或其他方式进行图片上传。在上传成功后,将图片地址返回给`success`函数;在上传失败时,调用`failure`函数并传递错误信息。 请注意,上述代码中的图片上传逻辑只是一个示例,你需要根据你的具体情况进行相应的修改。 引用: \[1\] 多图上传相关代码 \[2\] 图片上传的API地址 \[3\] 图片保存的逻辑代码 #### 引用[.reference_title] - *1* *2* [vite+vue3+tinymce实现单图上传和多图上传到阿里云oss](https://blog.csdn.net/deng_zhihao692817/article/details/125061332)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [2.0 vue2+tinymce+springboot实现图片上传与回显](https://blog.csdn.net/u013733643/article/details/130868762)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值