Tinymce的使用,下载包到本地方式

之前图快,直接使用cdn方式引用的tinymce文件,但是在使用过程中发现极易受网络影响,索性改成本地引用的方式,本地引用方式很多,可以npm下载,也可以向我这样官网下载,然后放在public文件夹内使用。
包括汉化、自定义图标、上传图片视频、解决在el-dialog中tinymce z-index 太小而被遮挡问题、解决打包后找不到文件的相关配置等

效果图

在这里插入图片描述

实现步骤

1、先下载tinymce文件包,我下载的是5.5版本的

下载地址:https://www.tiny.cloud/get-tiny/self-hosted/

在这里插入图片描述

2、将下载的文件解压缩,复制js目录里面tinymce文件夹到项目public目录下

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
tinymce文件夹内文件如上图蓝色框中所示

3、下载汉化包,将下载的汉化包放到langs文件夹下

在这里插入图片描述

4、设置自定义图标,比对icons目录下default文件夹中的js文件编写即可

在这里插入图片描述
在icons文件夹下创建custom目录,新建icons.js文件,在这个文件里面添加需要修改的图标即可
在这里插入图片描述
形式:

tinymce.IconManager.add('custom', {
  icons: {}
})

注:图标要使用svg代码,可以到阿里图标上复制相应的svg代码
icon对照表:https://blog.csdn.net/qq_34114082/article/details/90024080
在这里插入图片描述

5、准备就绪后,就是创建相应的组件

Tinymce组件的代码主要来自git的开源项目【https://github.com/PanJiaChen/vue-element-admin】,在其基础上进行了一些修改,实现图片视频上传,解决项目打包后找不到文件等问题,这里就不做赘述,直接贴代码了(index.vue),需要完整的自行到git开源项目下载
在这里插入图片描述

<!--
* @描述: 富文本编辑器组件:
* 引用public目录下文件在路径前面添加 process.env.BASE_URL,可避免打包后找不到静态文件的问题
* process.env.BASE_URL 为 vue.config.js里面配置的 publicPath
-->
<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'

import {
  uploadImg
} from '@/api/upload'
// 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'
// const tinymceCDN = 'http://lib.baomitu.com/tinymce/4.9.2/tinymce.min.js'
const tinymceCDN = process.env.BASE_URL + 'tinymce/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}`,
        // icons_url: '/tinymce/icons/custom/icons.js', // 如果需要自定义图标,到这个文件里面添加就行
        // icons: 'custom',
        language_url: process.env.BASE_URL + 'tinymce/langs/zh.js',
        language: 'zh',
        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,
        fontsize_formats: '12px 14px 16px 18px 24px 36px 48px 56px 72px',
        font_formats: '微软雅黑=Microsoft YaHei,Helvetica Neue,PingFang SC,sans-serif;苹果苹方=PingFang SC,Microsoft YaHei,sans-serif;宋体=simsun,serif;仿宋体=FangSong,serif;黑体=SimHei,sans-serif;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;',
        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_upload_handler: function(blobInfo, succFun, failFun) {
          var formData
          formData = new FormData()
          var file = blobInfo.blob() // 转化为易于理解的file对象
          formData.append('file', file, file.name)
          uploadImg(formData).then(res => {
            succFun(res.filenames)
          }).catch(err => {
            failFun('出现未知问题,刷新页面,或者联系程序员: ' + err)
          })
        },
        file_picker_types: 'media',
        file_picker_callback: function(cb, value, meta) {
          // 当点击meidia图标上传时,判断meta.filetype == 'media'有必要,因为file_picker_callback是media(媒体)、image(图片)、file(文件)的共同入口
          if (meta.filetype === 'media') {
            // 创建一个隐藏的type=file的文件选择input
            const input = document.createElement('input')
            input.setAttribute('type', 'file')
            input.onchange = function() {
              const file = this.files[0] // 只选取第一个文件。如果要选取全部,后面注意做修改
              var formData
              formData = new FormData()
              formData.append('file', file)
              uploadImg(formData).then(res => {
                // 接口返回的文件保存地址
                const mediaLocation = res.filenames
                // cb()回调函数,将mediaLocation显示在弹框输入框中
                cb(mediaLocation, {
                  title: file.name
                })
              }).catch(err => {
                console.log(err)
              })
            }
            // 触发点击
            input.click()
          }
        },
        // it will try to keep these URLs intact
        // https://www.tiny.cloud/docs-3x/reference/configuration/Configuration3x@convert_urls/
        // https://stackoverflow.com/questions/5196205/disable-tinymce-absolute-to-relative-url-conversions
        convert_urls: false
      })
    },
    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) {
      arr.forEach(v => window.tinymce.get(this.tinymceId).insertContent(`<img class="wscnph" src="${v.url}" >`))
    }
  }
}
</script>

<style lang="scss" scoped>
  .tinymce-container {
    position: relative;
    line-height: normal;
  }

  .tinymce-container {
    ::v-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>

<style>
/* 在el-dialog中tinymce z-index 被太小而被遮挡时要加这两句 */
.tox-tinymce-aux{z-index:99999 !important;}
.tinymce.ui.FloatPanel{z-Index: 99;}
</style>


图片视频上传具体实现可以看我另一篇文章,直接复制上面的文件可能没用,需要修改相应的接口调用:
https://blog.csdn.net/qq_43467284/article/details/130971345?spm=1001.2014.3001.5501
想省事的话也可以直接下载我处理好的tinymce文件,但是不推荐,自己写一遍也很快,而且印象也能深刻点,还能省积分
tinymce包下载链接:https://download.csdn.net/download/qq_43467284/88701525?spm=1001.2014.3001.5501
tinymce组件下载链接:https://download.csdn.net/download/qq_43467284/88701734?spm=1001.2014.3001.5503
上面的链接要是失效了就自己写吧,我不知道这个资源审核会不会通过

  • 7
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值