TinyMCE-vue 走过的坑

尉迟默
2023-12-01

缓存问题

建议一定要给selector, 如果容器是同一个,有可能会造成打开一个空的编辑器,里面却会有之前打开过的内容.

我这边直接封装一个父级容器,对它的id进行赋值,其值是时间戳

<div :id="selectorId">
    <editor v-if="!reloading" v-model="myValue" :init="init" :disabled="disabled" @onClick="onClick">
    </editor>
</div>
 selectorId: new Date().getTime(), //避免重复使用同一个div编辑器

上传文件至java后台,处理后进行回显到编辑器,出现无法显示

this.$emit('change', newValue)

tinymce有输入,改变两种模式.

通俗的说,输入就是,人为的直接在编辑器内输入,改变就是通过代码直接添加.

有了这个了解,就可以解决这个问题

//当triggerChange时true时,进行代码侵入,当时false时,用户输入模式

watch: {
      value(newValue) {
        this.myValue = (newValue == null ? '' : newValue)
      },
      myValue(newValue) {
        if (this.triggerChange) {
          this.$emit('change', newValue)
        } else {
          this.$emit('input', newValue)
        }
      }
    }

结合ant design vue 使用时,他的父级是a-modal,第一次点击显示时, 编辑器内为空,不能渲染

解决方法: 写一个reload的方法,监听 当他的父级是 a-modal时,执行reload

<div :id="selectorId">
    <editor v-if="!reloading" v-model="myValue" :init="init" :disabled="disabled" @onClick="onClick">
    </editor>
  </div>
reloading: false,
methods: {

      reload() {
        this.reloading = true
        this.$nextTick(() => this.reloading = false)
      },
      initATabsChangeAutoReload() {
        // 获取父级
        let modal = getVmParentByName(this,'AModal')
         if(modal){
          console.log("tinymce reload!")
          this.reload();
        }
      },
      }



mounted() {
      this.initATabsChangeAutoReload()
    },

附:完整代码 参考jeecgboot封装的j-editor


<template>
  <div :id="selectorId">
    <editor v-if="!reloading" v-model="myValue" :init="init" :disabled="disabled" @onClick="onClick">
    </editor>
  </div>
</template>

<script>
  import tinymce from 'tinymce/tinymce'
  import Editor from '@tinymce/tinymce-vue'
  import {
    setStore,
    getStore,
    clearStore
  } from "@/utils/storage"
  import "tinymce/icons/default/icons";
  import 'tinymce/themes/silver/theme'
  import 'tinymce/plugins/table'
  import 'tinymce/plugins/lists'
  // import 'tinymce/plugins/contextmenu'
  import 'tinymce/plugins/wordcount'
  // import 'tinymce/plugins/textcolor'
  import 'tinymce/plugins/fullscreen'
  // import 'tinymce/icons/default'
  import 'tinymce/plugins/advlist'
  import 'tinymce/plugins/preview'
  import 'tinymce/plugins/charmap'
  import 'tinymce/plugins/autosave'

  import {
    uploadAction,
    getFileAccessHttpUrl
  } from '@/api/manage'
  import {
    getVmParentByName
  } from '@/utils/util'
  export default {
    components: {
      Editor
    },
    name: "JEditor",
    props: {
      height: {
        type: Number,
        required: false,
        default: 500
      },
      width: {
        type: Number,
        required: false,
        default: 500
      },
      value: {
        type: String,
        required: false
      },
      triggerChange: {
        type: Boolean,
        default: false,
        required: false
      },
      disabled: {
        type: Boolean,
        default: false
      },
      plugins: {
        type: [String, Array],
        default: 'lists advlist charmap indent2em table wordcount preview fullscreen autosave'
      },
      toolbar: {
        type: [String, Array],
        default: 'undo redo |  formatselect removeformat | charmap bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | lists advlist table | preview restoredraft fullscreen',
        branding: false
      }
    },
    data() {
      return {
        //初始化配置
        init: {
          language_url: '/tinymce/langs/zh_CN.js',
          language: 'zh_CN',
          skin_url: '/tinymce/skins/lightgray',
          height: this.height,
          width: this.width,
          plugins: this.plugins,
          statusbar: false, //隐藏状态栏
          toolbar: this.toolbar,
          branding: false,
          menubar: true,
          autosave_restore_when_empty: true,
          autosave_interval: "20s",
          autosave_retention: "10080m",
          toolbar_drawer: "floating",
          images_upload_handler: (blobInfo, success) => {
            let formData = new FormData()
            formData.append('file', blobInfo.blob(), blobInfo.filename());
            formData.append('biz', "jeditor");
            formData.append("jeditor", "1");
            uploadAction(window._CONFIG['domianURL'] + "/sys/common/upload", formData).then((res) => {
              if (res.success) {
                if (res.message == 'local') {
                  const img = 'data:image/jpeg;base64,' + blobInfo.base64()
                  success(img)
                } else {
                  let img = getFileAccessHttpUrl(res.message)
                  success(img)
                }
              }
            })
          }
        },
        selectorId: new Date().getTime(), //避免重复使用同一个div编辑器
        myValue: this.value,
        reloading: false,
      }
    },
    mounted() {
      this.initATabsChangeAutoReload()
    },
    methods: {

      reload() {
        this.reloading = true
        this.$nextTick(() => this.reloading = false)
      },

      onClick(e) {
        this.$emit('onClick', e, tinymce)
      },
      //可以添加一些自己的自定义事件,如清空内容
      clear() {
        this.myValue = ''
      },

      /**
       * 自动判断父级是否是 <a-tabs/> 组件,然后添加事件监听,自动触发reload()
       *
       * 由于 tabs 组件切换会导致 tinymce 无法输入,
       * 只有重新加载才能使用(无论是vue版的还是jQuery版tinymce都有这个通病)
       */
      initATabsChangeAutoReload() {
        // 获取父级
        let tabs = getVmParentByName(this, 'ATabs')
        let tabPane = getVmParentByName(this, 'ATabPane')
        let modal = getVmParentByName(this,'AModal')
        if (tabs && tabPane ) {
          // 用户自定义的 key
          let currentKey = tabPane.$vnode.key
          // 添加事件监听
          tabs.$on('change', (key) => {
            // 切换到自己时执行reload
            if (currentKey === key) {
              this.reload()
            }
          })
        }else if(modal){
          console.log("tinymce reload!")
          this.reload();
        }
      },

    },
    watch: {
      value(newValue) {
        this.myValue = (newValue == null ? '' : newValue)
      },
      myValue(newValue) {
        if (this.triggerChange) {
          this.$emit('change', newValue)
        } else {
          this.$emit('input', newValue)
        }
      }
    }
  }
</script>
<style scoped>
</style>

还有几个坑,看这里TinyMCE-vue 组件实现上传word解析后返回到富文本编辑器中

 类似资料: