| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 | <template>  <div :class="{fullscreen:fullscreen}" class="tinymce-container" :style="{width:containerWidth}">    <textarea :id="tinymceId" class="tinymce-textarea" />    <div class="editor-custom-btn-container">      <editorImage color="#1890ff" class="editor-upload-btn" @successCBK="imageSuccessCBK" />    </div>  </div></template><script>/** * docs: * https://panjiachen.github.io/vue-element-admin-site/feature/component/rich-editor.html#tinymce */import editorImage from './components/EditorImage'import plugins from './plugins'import toolbar from './toolbar'import load from './dynamicLoadScript'// why use this cdn, detail see https://github.com/PanJiaChen/tinymce-all-in-oneconst tinymceCDN = 'https://cdn.jsdelivr.net/npm/tinymce-all-in-one@4.9.3/tinymce.min.js'export default {  name: 'Tinymce',  components: { editorImage },  props: {    id: {      type: String,      default: function() {        return 'vue-tinymce-' + +new Date() + ((Math.random() * 1000).toFixed(0) + '')      }    },    value: {      type: String,      default: ''    },    toolbar: {      type: Array,      required: false,      default() {        return []      }    },    menubar: {      type: String,      default: 'file edit insert view format table'    },    height: {      type: [Number, String],      required: false,      default: 360    },    width: {      type: [Number, String],      required: false,      default: 'auto'    }  },  data() {    return {      hasChange: false,      hasInit: false,      tinymceId: this.id,      fullscreen: false,      languageTypeList: {        'en': 'en',        'zh': 'zh_CN',        'es': 'es_MX',        'ja': 'ja'      }    }  },  computed: {    containerWidth() {      const width = this.width      if (/^[\d]+(\.[\d]+)?$/.test(width)) { // matches `100`, `'100'`        return `${width}px`      }      return width    }  },  watch: {    value(val) {      if (!this.hasChange && this.hasInit) {        this.$nextTick(() =>          window.tinymce.get(this.tinymceId).setContent(val || ''))      }    }  },  mounted() {    this.init()  },  activated() {    if (window.tinymce) {      this.initTinymce()    }  },  deactivated() {    this.destroyTinymce()  },  destroyed() {    this.destroyTinymce()  },  methods: {    init() {      // dynamic load tinymce from cdn      load(tinymceCDN, (err) => {        if (err) {          this.$message.error(err.message)          return        }        this.initTinymce()      })    },    initTinymce() {      const _this = this      window.tinymce.init({        selector: `#${this.tinymceId}`,        language: this.languageTypeList['en'],        height: this.height,        body_class: 'panel-body ',        object_resizing: false,        toolbar: this.toolbar.length > 0 ? this.toolbar : toolbar,        menubar: this.menubar,        plugins: plugins,        end_container_on_empty_block: true,        powerpaste_word_import: 'clean',        code_dialog_height: 450,        code_dialog_width: 1000,        advlist_bullet_styles: 'square',        advlist_number_styles: 'default',        imagetools_cors_hosts: ['www.tinymce.com', 'codepen.io'],        default_link_target: '_blank',        link_title: false,        nonbreaking_force_tab: true, // inserting nonbreaking space   need Nonbreaking Space Plugin        init_instance_callback: editor => {          if (_this.value) {            editor.setContent(_this.value)          }          _this.hasInit = true          editor.on('NodeChange Change KeyUp SetContent', () => {            this.hasChange = true            this.$emit('input', editor.getContent())          })        },        setup(editor) {          editor.on('FullscreenStateChanged', (e) => {            _this.fullscreen = e.state          })        }        // 整合七牛上传        // images_dataimg_filter(img) {        //   setTimeout(() => {        //     const $image = $(img);        //     $image.removeAttr('width');        //     $image.removeAttr('height');        //     if ($image[0].height && $image[0].width) {        //       $image.attr('data-wscntype', 'image');        //       $image.attr('data-wscnh', $image[0].height);        //       $image.attr('data-wscnw', $image[0].width);        //       $image.addClass('wscnph');        //     }        //   }, 0);        //   return img        // },        // images_upload_handler(blobInfo, success, failure, progress) {        //   progress(0);        //   const token = _this.$store.getters.token;        //   getToken(token).then(response => {        //     const url = response.data.qiniu_url;        //     const formData = new FormData();        //     formData.append('token', response.data.qiniu_token);        //     formData.append('key', response.data.qiniu_key);        //     formData.append('file', blobInfo.blob(), url);        //     upload(formData).then(() => {        //       success(url);        //       progress(100);        //     })        //   }).catch(err => {        //     failure('出现未知问题,刷新页面,或者联系程序员')        //     console.log(err);        //   });        // },      })    },    destroyTinymce() {      const tinymce = window.tinymce.get(this.tinymceId)      if (this.fullscreen) {        tinymce.execCommand('mceFullScreen')      }      if (tinymce) {        tinymce.destroy()      }    },    setContent(value) {      window.tinymce.get(this.tinymceId).setContent(value)    },    getContent() {      window.tinymce.get(this.tinymceId).getContent()    },    imageSuccessCBK(arr) {      const _this = this      arr.forEach(v => {        window.tinymce.get(_this.tinymceId).insertContent(`<img class="wscnph" src="${v.url}" >`)      })    }  }}</script><style scoped>.tinymce-container {  position: relative;  line-height: normal;}.tinymce-container>>>.mce-fullscreen {  z-index: 10000;}.tinymce-textarea {  visibility: hidden;  z-index: -1;}.editor-custom-btn-container {  position: absolute;  right: 4px;  top: 4px;  /*z-index: 2005;*/}.fullscreen .editor-custom-btn-container {  z-index: 10000;  position: fixed;}.editor-upload-btn {  display: inline-block;}</style>
 |