vue中使用富文本 tinymce

1.这是一个富文本组件

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

<script>
// import { api } from '@/api/api'
// 这里是请求接口的地方,当你需要上传图片的时候需要在这里配置请求-具体看代码改
// import { httpAction } from '@/api/manage'
const tinymceCDN = 'https://lib.baomitu.com/tinymce/5.1.2/tinymce.min.js'
// const tinymceCDN = 'https://cdnjs.cloudflare.com/ajax/libs/tinymce/5.1.2/tinymce.min.js';
const plugins = [
  'advlist anchor autolink autosave code codesample directionality emoticons fullscreen hr image imagetools insertdatetime link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace spellchecker tabfocus table template textpattern visualblocks wordcount'
]
const plugins2 = [
  'advlist anchor autolink autosave code codesample directionality emoticons fullscreen hr  insertdatetime link lists  nonbreaking noneditable pagebreak paste preview print save searchreplace spellchecker tabfocus table template textpattern visualblocks wordcount'
]
const toolbar = [
  'fontsizeselect formatselect searchreplace bold italic underline strikethrough alignleft aligncenter alignright outdent indent  blockquote undo redo removeformat subscript superscript hr bullist numlist link image charmap preview anchor pagebreak insertdatetime media table emoticons forecolor backcolor fullscreen'
]
function loadedTinymce() {
  return window.tinymce
}

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'
    },
    imgPass: {
      type: Boolean,
      required: false,
      default: false
    }
  },
  data() {
    return {
      // 这里是项目的后台接口地址,自己配置
      // requestUrl: process.env.VUE_APP_API_BASE_URL,
      imgFlag: false,
      imgArr: [],
      hasChange: false,
      hasInit: false,
      tinymceId: this.id,
      fullscreen: false,
      languageTypeList: {
        en: 'en',
        zh: 'zh_CN',
        es: 'es_MX',
        ja: 'ja'
      },
      // 这里是图片的上传接口地址,复制自己项目图片上传接口地址扔到这里
      imgApi: 'https://jsonplaceholder.typicode.com/posts/'
    }
  },
  computed: {
    language() {
      return this.languageTypeList['zh']
    },
    containerWidth() {
      const width = this.width
      if (/^[\d]+(\.[\d]+)?$/.test(width)) {
        return `${width}px`
      }
      return width
    }
  },
  watch: {
    value(val) {
      if (!this.hasChange && this.hasInit) {
        this.$nextTick(() => window.tinymce.get(this.tinymceId).setContent(val || ''))
      }
      // str是获取的富文本解析成html格式的文本内容
      const str = window.tinymce.activeEditor.getContent()
      // num是用正则获取到的纯文本内容(包括标点符号)
      const num = this.removeHTMLTag(str)
      this.$emit('textLength', num.length)
      if (num.length > 1000) {
        // this.Inputflag
        // this.$confirm('字符长度已超出上限1000个字符!', '提示', {
        //   confirmButtonText: '确定',
        //   cancelButtonText: '取消',
        //   type: 'warning'
        // });
      }
    },
    imgPass: {
      immediate: true,
      handler(newVal, oldValue) {
        this.imgFlag = newVal
      }
    },
    language() {
      this.destroyTinymce()
      this.$nextTick(() => this.initTinymce())
    }
  },
  mounted() {
    this.init()
  },
  activated() {
    if (window.tinymce) {
      this.initTinymce()
    }
  },
  deactivated() {
    this.destroyTinymce()
  },
  destroyed() {
    this.destroyTinymce()
  },
  methods: {
    // 提纯文本的方法
    removeHTMLTag: function(str) {
      str = str.replace(/<\/?[^>]*>/g, '')
      str = str.replace(/[ | ]*\n/g, '\n')
      str = str.replace(/&nbsp;/gi, '')
      str = str.replace(/\s/g, '')
      return str
    },
    init() {
      // dynamic load tinymce from cdn
      this.dynamicLoadScript(tinymceCDN, (err) => {
        if (err) {
          this.$message.error(err.message)
          return
        }
        this.initTinymce()
      })
    },
    initTinymce() {
      const _this = this
      // 具体配置信息可百度- -
      window.tinymce.init({
        // 配置 中文包 地址:这个包是扔在服务器上面的,然后直接请求服务器上面那个包地址就行了
        // language_url: 'http://192.168.0.xxx:xxxx/xxx/zh_CN.js',
        language: this.language,
        selector: `#${this.tinymceId}`,
        images_upload_url: _this.imgApi,
        height: this.height,
        body_class: 'panel-body ',
        object_resizing: false,
        toolbar: this.toolbar.length > 0 ? this.toolbar : toolbar,
        menubar: this.menubar,
        plugins: this.imgFlag ? plugins2 : 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: [
          process.env.VUE_APP_API_BASE_URL,
          // 'hhttp://192.168.0.xxx',
          'www.tinymce.com'
        ],
        default_link_target: '_blank',
        link_title: false,
        branding: true,
        statusbar: false,
        nonbreaking_force_tab: true, // inserting nonbreaking space &nbsp; need Nonbreaking Space Plugin
        autosave_ask_before_unload: true,
        autosave_interval: '30s',
        autosave_prefix: '{path}{query}-{id}-',
        autosave_restore_when_empty: false,
        autosave_retention: '2m',
        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_upload_handler(blobInfo, success, failure, progress) {
          progress(0)
          // 创建文件流
          const formData = new FormData()
          // 设置文件流参数
          formData.append('fileType', '0')
          formData.append('file', blobInfo.blob(), _this.imgApi)
          /* httpAction(_this.imgApi, formData, 'post').then((res) => {
            // 这里配置请求图片的地址是 'https://192.168.0.xxx:9999/file/?id=2323213123123123'
            // 根据实际项目需求自己配置 主要是 formData 这个文件流扔给后台
            success(_this.requestUrl + _this.imgApi.get + '?id=' + res.files[0].id)
            progress(100)
          }) */
        }
      })
    },
    destroyTinymce() {
      const tinymce = window.tinymce.get(this.tinymceId)
      if (this.fullscreen) {
        tinymce.execCommand('mceFullScreen')
      }

      if (tinymce) {
        tinymce.destroy()
      }
    },
    setContent(value) {
      this.$nextTick(() => {
        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}" >`)
      })
    },
    dynamicLoadScript(src, callback) {
      let callbacks = []
      const existingScript = document.getElementById(src)
      const cb = callback || function() {}

      if (!existingScript) {
        const script = document.createElement('script')
        script.src = src
        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
        }
      }
    }
  }
}
</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>

2 这里是引用

<template>
  <div>
    <div
      style="max-width: 1000px; min-width: 500px; padding: 3px 1px"
    >
      <tinymce :id="tinymceId" v-model="tinymce" :height="426" />
    </div>
  </div>
</template>

<script>
import tinymce from '@/components/tinymce'
export default {
  components: {
    tinymce
  },
  data() {
    return {
      tinymceId: '1',
      tinymce: ''
    }
  }
}
</script>

<style lang="scss" scoped>
</style>

3 结果图

在这里插入图片描述
1.之所以是英文的是因为没有设置服务器中文包地址,代码里面有介绍
2.配置图片上传这个得自己加上自己项目里面的图片上传地址 和图片回显地址,直接 搜索 image, requestUrl。贼简单
3.如果出现多个富文本的时候 请用v-if去显示隐藏它,必须要让它销毁了才会创建新的,有的弹框需要先创建弹框再创建富文本,也就是需要两个v-if,里面的id可以去看看
4.这个是古老写法,cdn加速那种,tinymce是支持npm去下载包的写法的,具体可以去研究一下,配置项基本大差不差

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
Vue.js 2.x 与 tinymce 富文本编辑器的集成相对简单。以下是一些步骤可以帮助你在 Vue.js 2.x 使用 tinymce: 1. 安装 tinymce:你可以通过 npm 或 yarn 安装 tinymce,运行以下命令: ```bash npm install tinymce # 或 yarn add tinymce ``` 2. 在组件引入 tinymce 并初始化: ```vue <template> <div> <textarea v-model="content" :id="editorId"></textarea> </div> </template> <script> import tinymce from 'tinymce/tinymce'; export default { data() { return { content: '', editorId: 'my-editor', // 指定一个唯一的 id }; }, mounted() { tinymce.init({ selector: `#${this.editorId}`, plugins: 'advlist autolink lists link image charmap print preview hr anchor', toolbar: 'undo redo | formatselect | bold italic backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | removeformat | image', height: 500, setup: (editor) => { editor.on('change', () => { this.content = editor.getContent(); }); }, }); }, beforeDestroy() { tinymce.get(this.editorId).destroy(); }, }; </script> ``` 在上述示例,我们在 mounted 钩子初始化了 tinymce 编辑器,并且使用 v-model 指令将编辑器的内容绑定到 Vue 实例上的 content 属性。在 beforeDestroy 钩子,我们销毁了 tinymce 编辑器。 你可以根据需要调整 tinymce 的配置项以满足你的需求。可以在 tinymce 的官方文档了解更多配置选项和插件的使用方法:[https://www.tiny.cloud/docs/](https://www.tiny.cloud/docs/) 希望这能帮到你!如果有任何问题,请随时提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值