tinymce公式提交问题

创建公式后生成base64格式的图片,与普通上传图片冲突,需要单独上传

1、判断需要上传的文件是否为普通文件,可以按照文件名称来判断,公式文件没有名称

images_upload_handler中打印:console.log(blobInfo.blob())

普通文件返回:

公式文件返回:

2、提取

源文件:提取后:

 注:这里从富文本中提取的所有图片文件,每次上传后src都会变成文件链接

3、取出数组中base64文件

result.forEach(element => {

  if (element.url.indexOf('data:image/png;base64,') > -1) {

    bytes = element.url

  }

})

4、上传

const config = {

  headers: {

    'Content-Type': 'multipart/form-data',

    accesscode: $cookies.get('accesscode')

  }

}

axios.post(url, data, config).then(res => {

  if (res.data.code === 200) {

    resolve(res.data.data.url) // 上传成功,在成功函数里填入图片路径

  } else {

    reject('上传失败' + res.data.message)

  }

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

 

完整代码:

// src/components/teditor.vue
<template>
  <editor v-model="myValue" :init="init" :disabled="disabled" :id="tinymceId"></editor>
</template>

<script setup lang="ts">
// 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 { reactive, ref } from 'vue'
import { onMounted, defineEmits, watch } from '@vue/runtime-core'
import axios from '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
  },
  height: {
    type: Number,
    default: 145
  },
  plugins: {
    type: [String, Array],
    default: 'print preview searchreplace autolink directionality visualblocks visualchars fullscreen image link kityformula-editor media template code codesample table charmap hr pagebreak nonbreaking anchor insertdatetime advlist lists wordcount textpattern autosave '
  }, // 必填
  toolbar: {
    type: [String, Array],
    default:
      'code fullscreen | undo redo | codesample bold italic outdent indent | image kityformula-editor'
  } // 必填
})
// 用于接收外部传递进来的富文本
const myValue = ref(props.value)
const tinymceId = ref('vue-tinymce-' + +new Date() + ((Math.random() * 1000).toFixed(0) + ''))
// 定义一个对象 init初始化
const init = reactive({
  selector: '#' + tinymceId.value, // 富文本编辑器的id,
  language_url: '/tinymce/langs/zh_CN.js', // 语言包的路径,具体路径看自己的项目,文档后面附上中文js文件
  language: 'zh_CN', // 语言
  skin_url: '/tinymce/skins/ui/oxide', // skin路径,具体路径看自己的项目
  width: '100%', // 编辑器宽度
  height: props.height, // 编辑器高度
  branding: false, // 是否禁用“Powered by TinyMCE”
  menubar: false, // 顶部菜单栏显示
  statusbar: false, // 底部状态栏显示
  automatic_uploads: true, // 图片自动上传
  image_dimensions: false, // 去除宽高属性
  plugins: props.plugins, // 这里的数据是在props里面就定义好了的
  toolbar: props.toolbar, // 这里的数据是在props里面就定义好了的
  menu: {
    edit: { title: '编辑', items: 'undo redo selectall' },
    insert: { title: '插入', items: 'image kityformula-editor | charmap emoticons hr | pagebreak nonbreaking anchor tableofcontents | insertdatetime' },
    format: { title: '格式', items: 'bold italic underline strikethrough | formats | styles blocks fontfamily fontsize align lineheight | forecolor backcolor | language | blockquote subscript superscript removeformat' },
    tools: { title: '工具', items: 'spellchecker spellcheckerlanguage | a11ycheck code wordcount' },
    table: { title: '表格', items: 'inserttable | cell row column | advtablesort | tableprops deletetable' }
  },
  font_formats: 'Arial=arial,helvetica,sans-serif; 宋体=SimSun; 微软雅黑=Microsoft Yahei; Impact=impact,chicago;', // 字体
  fontsize_formats: '11px 12px 14px 16px 18px 24px 36px 48px 64px 72px', // 文字大小
  paste_convert_word_fake_lists: false, // 插入word文档需要该属性
  paste_webkit_styles: 'all',
  paste_merge_formats: true,
  nonbreaking_force_tab: false,
  paste_auto_cleanup_on_paste: false,
  file_picker_types: 'file',
  content_css: '/tinymce/skins/content/default/content.css', // 以css文件方式自定义可编辑区域的css样式,css文件需自己创建并引入
  // 图片上传
  images_upload_handler: (blobInfo) => new Promise((resolve, reject) => {
    if (blobInfo.blob().size / 1024 / 1024 > 2) {
      reject({ message: '上传失败,图片大小请控制在 2M 以内', remove: true })
    } else {
      const ph = process.env.VUE_APP_BASE_API
      const params = new FormData()
      params.append('file', blobInfo.blob())
      params.append('fwjjmc', 'public')
      params.append('wjjmc', 'fuwenben')

      const config = {
        headers: {
          'Content-Type': 'multipart/form-data',
          accesscode: $cookies.get('accesscode')
        }
      }
      if (blobInfo.blob().name) {
        axios.post(`${process.env.VUE_APP_BASE_API}/api/v2/sys/wenjian/upload`, params, config).then(res => {
          if (res.data.code === 200) {
            resolve(ph + res.data.data.lj + res.data.data.mc) // 上传成功,在成功函数里填入图片路径
          } else {
            reject('上传失败' + res.data.message)
          }
        }).catch(() => {})
      } else {
        const patt = /<img[^>]+src=['"]([^'"]+)['"]+/g
        const result = []
        let bytes = ''
        let temp
        while ((temp = patt.exec(myValue.value)) !== null) {
          result.unshift({ url: temp[1] })
        }
        result.forEach(element => {
          if (element.url.indexOf('data:image/png;base64,') > -1) {
            bytes = element.url
          }
        })
        axios.post(`${process.env.VUE_APP_BASE_API}/api/v2/sys/wenjian/upload/gongshi`, { bytes: bytes, fwjjmc: 'public', wjjmc: 'fuwenben' }, config).then(res => {
          if (res.data.code === 200) {
            resolve(ph + res.data.data.lj + res.data.data.mc) // 上传成功,在成功函数里填入图片路径
          } else {
            reject('上传失败' + res.data.message)
          }
        }).catch(() => {})
      }
    }
  }),

  // 文件上传
  file_picker_callback: (callback, value, meta) => {
    // 文件分类
    const filetype = '.pdf, .txt, .zip, .rar, .7z, .doc, .docx, .xls, .xlsx, .ppt, .pptx, .mp3, .mp4'
    // 后端接收上传文件的地址
    const upurl = `${process.env.VUE_APP_BASE_API}/file/v2/upload?accesscode=${$cookies.get('accesscode')}`
    // 模拟出一个input用于添加本地文件
    const input = document.createElement('input')
    input.setAttribute('type', 'file')
    input.setAttribute('accept', filetype)
    input.click()
    input.onchange = function () {
      const file = this.files[0]

      const xhr = new XMLHttpRequest()
      xhr.withCredentials = false
      xhr.open('POST', upurl)
      xhr.onload = function () {
        if (xhr.status !== 200) {
          failure('HTTP Error: ' + xhr.status)
          return
        }
        const json = JSON.parse(xhr.responseText)
        if (!json || typeof json.data.showPath !== 'string') {
          failure('Invalid JSON: ' + xhr.responseText)
          return
        }
        const showPath = process.env.VUE_APP_BASE_API + json.data.showPath
        callback(showPath)
      }
      const formData = new FormData()
      formData.append('file', file, file.name)
      formData.append('fwjjmc', 'public')
      formData.append('wjjmc', 'fuwenben')
      xhr.send(formData)
    }
  }
})
function dataURLtoBlob (dataurl) {
  const arr = dataurl.split(','); const mime = arr[0].match(/:(.*?);/)[1]
  const bstr = atob(arr[1]); let n = bstr.length; const u8arr = new Uint8Array(n)
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n)
  }
  return new Blob([u8arr], { type: mime })
}

function downloadFile (url, name) {
  const a = document.createElement('a') // 新建一个a链接
  a.setAttribute('href', url) // a链接的url为图片的url
  a.setAttribute('download', name)
  a.setAttribute('target', '_blank')
  const clickEvent = document.createEvent('MouseEvents')
  clickEvent.initEvent('click', true, true)
  a.dispatchEvent(clickEvent)
}

// 73so.com
function downloadFileByBase64 (base64, name) {
  const myBlob = dataURLtoBlob(base64)
  const myUrl = URL.createObjectURL(myBlob) // 创建图片的临时url
  downloadFile(myUrl, name)
}
// 监听外部传递进来的的数据变化
watch(
  () => props.value,
  () => {
    myValue.value = props.value
    emits('getContent', myValue.value)
  }
)
// 监听富文本中的数据变化
watch(
  () => myValue.value,
  () => {
    emits('getContent', myValue.value)
  }
)
// 在onMounted中初始化编辑器
onMounted(() => {
  tinymce.init({})
})
</script>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值