vue引入富文本框编辑器-tinymce.min.js库

效果图

该编辑器引用了tinymce.min.js库

GitHub - PanJiaChen/tinymce-all-in-one: Build all tinymce plugins into one jsBuild all tinymce plugins into one js. Contribute to PanJiaChen/tinymce-all-in-one development by creating an account on GitHub.icon-default.png?t=N7T8https://github.com/PanJiaChen/tinymce-all-in-one

一.在components目录下定义Tinymce组件

1. plugins.js

// 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

2. toolbar.js

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

const toolbar = ['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

3. dynamicLoadScript.js

let callbacks = []

function loadedTinymce() {
  // to fixed https://github.com/PanJiaChen/vue-element-admin/issues/2144
  // check is successfully downloaded script
  return window.tinymce
}

const dynamicLoadScript = (src, callback) => {
  const existingScript = document.getElementById(src)
  const cb = callback || function() {}

  if (!existingScript) {
    const script = document.createElement('script')
    script.src = src // src url for the third-party library being loaded.
    script.id = src
    document.body.appendChild(script)
    callbacks.push(cb)
    const onEnd = 'onload' in script ? stdOnEnd : ieOnEnd
    onEnd(script)
  }

  if (existingScript && cb) {
    if (loadedTinymce()) {
      cb(null, existingScript)
    } else {
      callbacks.push(cb)
    }
  }

  function stdOnEnd(script) {
    script.onload = function() {
      // this.onload = null here is necessary
      // because even IE9 works not like others
      this.onerror = this.onload = null
      for (const cb of callbacks) {
        cb(null, script)
      }
      callbacks = null
    }
    script.onerror = function() {
      this.onerror = this.onload = null
      cb(new Error('Failed to load ' + src), script)
    }
  }

  function ieOnEnd(script) {
    script.onreadystatechange = function() {
      if (this.readyState !== 'complete' && this.readyState !== 'loaded') return
      this.onreadystatechange = null
      for (const cb of callbacks) {
        cb(null, script) // there is no way to catch loading errors in IE8
      }
      callbacks = null
    }
  }
}

export default dynamicLoadScript

4. index.vue

<template>
  <div :class="{ fullscreen: fullscreen }" class="tinymce-container" :style="{ width: containerWidth }">
    <textarea :id="tinymceId" class="tinymce-textarea" />
  </div>
</template>

<script>
/**
 * docs:
 * https://panjiachen.github.io/vue-element-admin-site/feature/component/rich-editor.html#tinymce
 */
import plugins from "./plugins.js";
import toolbar from "./toolbar.js";
import load from "./dynamicLoadScript.js";

// why use this cdn, detail see https://github.com/PanJiaChen/tinymce-all-in-one
const tinymceCDN =
  "https://cdn.jsdelivr.net/npm/tinymce-all-in-one@4.9.3/tinymce.min.js";

export default {
  name: "Tinymce",
  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: {
    language() {
      //return this.languageTypeList[this.$store.getters.language]
      return "zh_CN";
    },
    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 || "")
        );
      }
    },
    language() {
      this.destroyTinymce();
      this.$nextTick(() => this.initTinymce());
    },
  },
  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({
        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,
        end_container_on_empty_block: true,
        // powerpaste_word_import: "clean",
        code_dialog_height: 450,
        code_dialog_width: 1000,
        powerpaste_word_import: 'merge',
        paste_data_images: true,
        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);
          let formData = new FormData();
          formData.append('files', blobInfo.blob());
          _this.$http.upload('/api/file/uploads', formData).then(res => {
            success(process.env.VUE_APP_IMG + res.data.imgPath);
            progress(100);
          })
          return
          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('files', 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();
    },
  },
};
</script>

<style scoped>
.tinymce-container {
  position: relative;
  line-height: normal;
  box-shadow: 0 2px 4px 0 rgb(0 0 0 / 12%), 0 0 6px 0 rgb(0 0 0 / 4%);
}

.tinymce-container :deep(.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>

二.在页面文件引入组件使用

1.在script脚本里面引入、注册组件

import Tinymce from '/@/components/Tinymce/index.vue';

components: { Tinymce },

2.在template模板使用组件

 <tinymce :value="ruleForm.content"></tinymce>

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
安装tinymce需要以下步骤: 1. 安装tinymce依赖包 ```bash npm install tinymce --save ``` 2. 在Vue组件中引入tinymce ```javascript import tinymce from 'tinymce/tinymce' import 'tinymce/themes/silver/theme' import 'tinymce/plugins/advlist' import 'tinymce/plugins/autolink' import 'tinymce/plugins/lists' import 'tinymce/plugins/link' import 'tinymce/plugins/image' import 'tinymce/plugins/charmap' import 'tinymce/plugins/print' import 'tinymce/plugins/preview' import 'tinymce/plugins/hr' import 'tinymce/plugins/anchor' import 'tinymce/plugins/pagebreak' import 'tinymce/plugins/searchreplace' import 'tinymce/plugins/wordcount' import 'tinymce/plugins/visualblocks' import 'tinymce/plugins/visualchars' import 'tinymce/plugins/code' import 'tinymce/plugins/fullscreen' import 'tinymce/plugins/insertdatetime' import 'tinymce/plugins/media' import 'tinymce/plugins/nonbreaking' import 'tinymce/plugins/table' import 'tinymce/plugins/contextmenu' import 'tinymce/plugins/directionality' import 'tinymce/plugins/emoticons' import 'tinymce/plugins/template' export default { components: { tinymce } } ``` 3. 在Vue组件中使用tinymce ```html <template> <div> <tinymce v-model="content" :init="initSettings"></tinymce> </div> </template> <script> export default { data() { return { content: '', initSettings: { height: 500, menubar: false, plugins: [ 'advlist autolink lists link image charmap print preview hr anchor pagebreak', 'searchreplace wordcount visualblocks visualchars code fullscreen', 'insertdatetime media nonbreaking table contextmenu directionality', 'emoticons template paste textcolor colorpicker textpattern imagetools codesample toc help' ], toolbar: 'undo redo | formatselect | bold italic backcolor | \ alignleft aligncenter alignright alignjustify | \ bullist numlist outdent indent | removeformat | help', content_css: [ '//fonts.googleapis.com/css?family=Lato:300,300i,400,400i', '//www.tiny.cloud/css/codepen.min.css' ] } } } } </script> ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值