在vue2使用TinyMCE富文本编辑器

tiny中文文档

安装

npm i tinymce@5.10.9 -S
npm i @tinymce/tinymce-vue@3.0.1 -S

在public文件下创建tinymce文件夹(需要包含langs和skins)

【注意】:vue2使用tinymce富文本编辑器在node_modules直接引用中文包合skins下的样式好像不起作用,放在public下去引入就没问题
tinymce文件夹目录

  • 在node_modules中tinymce依赖包,找到其下面的skins文件下,直接复制,粘贴到src/assets/tinymce目录下;
  • 先到官网下载中文翻译文件备用,将下载的zh_CN.js文件放在langs文件夹下;
    官网
    中文包

封装组件tinymce.vue

<template>
  <div>
    <editor
      v-model="myValue"
      :init="init"
      :disabled="disabled"
      @onClick="onClick"
    >
    </editor>
  </div>
</template>

<script>
import tinymce from "tinymce/tinymce";
import Editor from "@tinymce/tinymce-vue";
import "tinymce/skins/ui/oxide/skin.css";
import "tinymce/themes/silver/theme";
import 'tinymce/icons/default/icons'
import "tinymce/icons/default"; // 图标 -解决测试环境找不icon问题
//下面这些引入路径中带plugins的都是引入安装的依赖包里面的插件;
//如果你想使用和展示该插件功能,就要先引入
import 'tinymce/plugins/autolink'
import "tinymce/plugins/image";
import 'tinymce/plugins/media'
import 'tinymce/plugins/autoresize'
import 'tinymce/plugins/insertdatetime'
import 'tinymce/plugins/link'
import 'tinymce/plugins/code'
import 'tinymce/plugins/searchreplace'
import 'tinymce/plugins/table'
import "tinymce/plugins/lists";
import "tinymce/plugins/contextmenu";
import "tinymce/plugins/wordcount";
import "tinymce/plugins/colorpicker";
import "tinymce/plugins/textcolor";
import "tinymce/plugins/fullscreen";
import "tinymce/plugins/hr";
import "tinymce/plugins/preview";
import "tinymce/plugins/print";

import apiCommon from '@/api/common'

export default {
  name: "tinymce",
  components: {
    Editor,
  },
  props: {
    //传入一个value,使组件支持v-model绑定
    value: {
      type: String,
      default: "",
    },
    disabled: {
      type: Boolean,
      default: false,
    },
    // 配置要使用的插件:
    plugins: {
      type: [String, Array],
      default:
        "autolink autoresize fullscreen image insertdatetime link lists media preview table wordcount code searchreplace",
    },
    // 配置工具栏:
    toolbar: {
      type: [String, Array],
      default:
          "undo redo | " +
          "blocks | " +
          "formatselect fontselect fontsizeselect | " +
          "lineheight  | " +
          "bold italic underline strikethrough | "+
          "alignleft aligncenter alignright alignjustify | "+
          "forecolor backcolor removeformat | "+
          "bullist numlist outdent indent | "+
          "link image media table insertdatetime searchreplace | "+
          "preview fullscreen print | ",
    },
  },
  data() {
    return {
      //初始化配置
      init: {
        selector: 'textarea',
        // 配置中文:
        language_url: '/tinymce/langs/zh_CN.js', // 这里需要单独处理(在官网下载语言包放在publici文件下,不然会出现引入找不到问题)
        language: 'zh_CN',
        // skin_url: '/tinymce/skins/ui/oxide',  // 这样有问题
        // content_css: 'tinymce/skins/content/default/content.min.css', // 这样有问题
        skin_url: '/tinymce/skins/ui/oxide', // 这里需要单独处理(在官网下载语言包放在publici文件下,不然会出现引入找不到问题)
        content_css: '/tinymce/skins/content/default/content.min.css', // 这里需要单独处理(在官网下载语言包放在publici文件下,不然会出现引入找不到问题)
        min_height: 250,
        max_height: 600,
        plugins: this.plugins,
        toolbar: this.toolbar,
        branding: false,
        menubar: false,
        toolbar_mode: 'sliding',
        insertdatetime_formats: [
          '%Y年%m月%d日',
          '%H点%M分%S秒',
          '%Y-%m-%d',
          '%H:%M:%S',
        ],
        // 默认单位是pt,现改为px
        font_size_formats: '9px 10px 11px 12px 14px 16px 18px 20px 22px 24px 26px 28px 36px 42px 48px 72px',
		// 配置工具栏时添加的 fontsizeinput 工具可以展示一个可输入字号的组件,默认单位是pt,现改为px
		font_size_input_default_unit: 'px',
        // 官网地址:https://www.tiny.cloud/docs/tinymce/6/file-image-upload/#images_upload_handler
        // 自定义图像和文件的处理方式
        images_upload_handler: (blobInfo, success, failure) => {
          let formData = new FormData()
          formData.append('multipartFiles', blobInfo.blob(), blobInfo.filename())
          apiCommon.uploadFileApi(formData).then(res=>{//使用axios进行图片上传,注意this是否引入成功
            const [url] = res.data
            success(url)
          }).catch(()=>{
            failure("上传出错,服务器开小差了呢")
          })
        },
        //自定义文件选择器的回调内容
        file_picker_callback(callback, value, meta) {
          if (meta.filetype === 'media') {
            // 模拟上传本地视频
            const input = document.createElement('input')
            input.setAttribute('type', 'file')
            input.setAttribute('accept', '.mp4')
            input.onchange = function (e) {
              const file = e.target.files[0]
              const formData = new FormData()
              formData.append('multipartFiles', file, file.name)
              // 请求文件上传接口
              apiCommon.uploadFileApi(formData).then((res) => {
                const [url] = res.data
                callback(url)
              })
            }
            input.click()
          }
          if (meta.filetype === 'image') {
            // 模拟上传本地图片
            const input = document.createElement('input')
            input.setAttribute('type', 'file')
            input.setAttribute('accept', '.png,.jpg,.jpeg,.jpeg,.gif,.bmp,.webp')
            input.onchange = function (e) {
              const file = e.target.files[0]
              const formData = new FormData()
              formData.append('multipartFiles', file, file.name)
              // 请求文件上传接口
              apiCommon.uploadFileApi(formData).then((res) => {
                const [url] = res.data
                callback(url)
              })
            }
            input.click()
          }
        },
        // //设置默认展示的字体和字号
        // setup: function(editor) {
        //    editor.on('init', function(ed) {
        //         this.getBody().style.fontSize = '16px';
        //         this.getBody().style.fontFamily = '微软雅黑';
        //     });
        // },
        resize: true,
      },
      myValue: this.value,
    };
  },
  mounted() {
    tinymce.init({});
  },
  methods: {
    onClick(e) {
      this.$emit("onClick", e, tinymce);
    },
    clear() {
      this.myValue = "";
    },
  },
  watch: {
    value(newValue) {
      this.myValue = newValue;
    },
    myValue(newValue) {
      this.$emit("input", newValue);
    },
  },
};
</script>
<style lang="less" scoped>
.preview {
  margin-top: 10px;

  &::before {
    display: block;
    content: "预览:";
  }
}
</style>
<style lang="less">
// 提高TinyMCE下拉菜单的层级
.tox-tinymce-aux {
  z-index: 10000 !important;
}
// 全屏层级
// .tox-fullscreen {
//   z-index: 2001 !important;
// }

.tox-tbtn--bespoke {
  background: #f7f7f7 !important;
  height: 28px !important;
  line-height: 28px !important;
  margin-right: 10px !important;
  &:last-child {
    margin-right: 0 !important;
  }
}
</style>

组件中使用封装组件tinymce.vue

<Tinymce v-model="newsForm.content" />

遇到的问题

1、层级问题

如果在element-ui等组件库的弹窗使用TinyMCE编辑器时,可能TinyMCE提示框或下拉菜单等的层级比弹窗组件层级低而不会显示。因此需要提高TinyMCE下拉菜单的层级:

<style lang="less">
	.tox-tinymce-aux {
	  z-index: 10000 !important;
	}
</style>

2、tinymce中使用media,视频保存到编辑区域时,会出现两个video,点击空白会消失一个,再点击video又出现两个,并且没有官方那个可以自己缩放的效果

在这里插入图片描述
【原因】:skins下的东西没有正确引入,就入上面所说直接引入skins下的会报错,要把skins放在public下去引入

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值