vue使用 Tinymce富文本编辑器

1,目录结构
vue使用 Tinymce富文本编辑器
2.index.vue

<template>
  <div :class="{fullscreen:fullscreen}" class="tinymce-container editor-container">
    <textarea :id="tinymceId" class="tinymce-textarea" />
    <div class="editor-custom-btn-container">
      <editorImage color="#1890ff" class="editor-upload-btn" @successCBK="imageSuccessCBK" />
      <editorVideo color="#1890ff" class="editor-upload-btn" @successCBK="VideoSuccessCBK" />
    </div>
  </div>
</template>

<script>
import editorImage from './components/EditorImage'
import editorVideo from './components/EditorVideo'
import plugins from './plugins'
import toolbar from './toolbar'

export default {
  name: 'Tinymce',
  components: { editorImage,editorVideo},
  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,
      required: false,
      default: 360
    }
  },
  data() {
    return {
      hasChange: false,
      hasInit: false,
      tinymceId: this.id,
      fullscreen: false,
      languageTypeList: {
        'en': 'en',
        'zh': 'zh_CN'
      }
    }
  },
  computed: {
    language() {
      return this.languageTypeList[this.$store.getters.language]
    }
  },
  watch: {
    value(val) {
      if (!this.hasChange && this.hasInit) {
        this.$nextTick(() =>
          window.tinymce.get(this.tinymceId).setContent(val || ''))
      }
    },
    language() {
      this.destroyTinymce()
      this.$nextTick(() => this.initTinymce())
    }
  },
  mounted() {
    this.initTinymce()
  },
  activated() {
    this.initTinymce()
  },
  deactivated() {
    this.destroyTinymce()
  },
  destroyed() {
    this.destroyTinymce()
  },
  methods: {
    initTinymce() {
      const _this = this
      window.tinymce.init({
        language: this.language,
        selector: `#${this.tinymceId}`,
        height: this.height,
        body_class: 'panel-body ',
        object_resizing: false,
        toolbar: this.toolbar.length > 0 ? this.toolbar : toolbar,
        menubar: this.menubar,
        plugins: plugins,
        fontsize_formats: "8px 9px 10px 11px 12px 13px 14px 15px 16px 17px 18px 19px 20px 21px 22px 23px 24px 25px 26px 27px 28px 29px 30px 31px 32px 33px 34px 35px 36px 37px 38px",
        end_container_on_empty_block: true,
        powerpaste_word_import: 'clean',
        code_dialog_height: 400,
        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 &nbsp; 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" style="width:100%;display:block" src="${v.url}" >`)
      })
    },
    VideoSuccessCBK(arr){
        const _this = this
      arr.forEach(v => {
        window.tinymce.get(_this.tinymceId).insertContent(`<span class="mce-preview-object mce-object-video" contenteditable="false" data-mce-object="video" data-mce-p-controls="controls" data-mce-html="<source src='${v.url}' />"><video src="${v.url}" controls="controls" width="100%" height="auto" frameborder="0"></video><span class="mce-shim"></span></span>`)
      })
    }
  }
}
</script>

<style scoped>
.tinymce-container {
  position: relative;
  line-height: normal;
}
.tinymce-container>>>.mce-fullscreen {
  z-index: 10000;
}
.wscnph{
  width: 100%;
}
.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;
}
.mce-container{
  white-space: normal !important;
}
.mce-container, .mce-container *, .mce-widget, .mce-widget *, .mce-reset{
  white-space: normal !important;
}
</style>
<style>
.mce-container, .mce-container *, .mce-widget, .mce-widget *, .mce-reset{
  white-space: normal !important;
}
</style>

3,上传视频组件

<template>
  <div class="upload-container">
    <el-button :style="{background:color,borderColor:color}" icon="el-icon-upload" size="mini" type="primary"
      @click=" dialogVisible=true">上传视频</el-button>
    <el-dialog :append-to-body="true" :visible.sync="dialogVisible">
      <div class="dialog-bodyer">
        <upload @getImg="getImg"   accept=".mp4, .ogg" @delImg="delImg" :isVideo="true" :file-list="uploadFileList"
          uploadNotice="请上传视频,上传成功之前请不要关闭此窗口"></upload>
      </div>
      <div class="dialog-footer">
        <el-button @click="dialogVisible = false">取消</el-button>
        <el-button type="primary" @click="handleSubmit">确认</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>

import upload from "@/components/upload/upload";
  export default {
    name: "EditorSlideUploadVideo",
    props: {
      color: {
        type: String,
        default: "#1890ff",
      },
    },
    components: {
      upload,
    },
    data() {
      return {
        uploadUrl:"/oss/service/upload/imgNoParams",
        dialogVisible: false,
        listObj: {},
        fileList: [],
        uploadFileList: [],
      
        params: {},
      };
    },
    methods: {
      // data为图片地址
      getImg(data) {
        console.log(data, "datadatadatadatadatadatadata")
        this.$message({
          type: "success",
          message: `上传成功`,
        });
        // this.handleSubmit()
      },
      delImg(index) {
        // this.models.picture = "";

      },
      checkAllSuccess() {
        return Object.keys(this.listObj).every(
          (item) => this.listObj[item].hasSuccess
        );
      },
      handleSubmit() {
        if (!this.checkAllSuccess()) {
          this.$message(
            "Please wait for all images to be uploaded successfully. If there is a network problem, please refresh the page and upload again!"
          );
          return;
        }
        this.$emit("successCBK", this.uploadFileList);
        this.uploadFileList = [];
        this.dialogVisible = false;
      },
    },
  };

</script>

<style lang="scss" scoped>
  .dialog-footer {
    padding: 20px;
  }

  .dialog-bodyer {
    padding: 20px;
  }

  .editor-slide-upload {
    margin-bottom: 20px;

    /deep/ .el-upload--picture-card {
      width: 100%;
    }
  }

</style>

4.plugins

// Any plugins you want to use has to be imported
// Detail plugins list see https://www.tinymce.com/docs/plugins/
// Custom builds see https://www.tinymce.com/download/custom-builds/

const plugins = ['advlist anchor autolink autosave code codesample colorpicker colorpicker contextmenu directionality emoticons fullscreen hr image imagetools insertdatetime link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace spellchecker tabfocus table template textcolor textpattern visualblocks visualchars wordcount']

export default plugins

5,toolbar

// Here is a list of the toolbar
// Detail list see https://www.tinymce.com/docs/advanced/editor-control-identifiers/#toolbarcontrols

const toolbar = ['fontsizeselect fontselect searchreplace bold italic underline strikethrough alignleft aligncenter alignright outdent indent  blockquote undo redo removeformat subscript superscript code codesample', 'hr bullist numlist link image charmap preview anchor pagebreak insertdatetime media table emoticons forecolor backcolor fullscreen']

export default toolbar

上一篇:LifseaOS 悄然来袭,一款为云原生而生的 OS


下一篇:如何优化switch case语句?