Experience on the use of tinymce rich text editor

This article is divided into the following functions:

  1. Some configurations for tinymce initialization
  2. Insert specific titles and summaries between toolbars and text
  3. Customize toolbar buttons to achieve specific functions
  4. Remove the network upload function when uploading pictures
  5. The pasted pictures are uploaded by default
  6. Add watermark function to pictures
  7. Realize one-click typesetting

    1. Some configurations of tinymce initialization

          1. First, you need to introduce the following two plug-ins

        cnpm install @tinymce/tinymce-vue --save Version: 2.0.0

        cnpm install tinymce --save Version: 5.0.3
        Note: When I used it before, I found that some built-in plug-ins did not exist in tinymce 6 and above versions, which caused some functions to be unavailable, so I marked the version here

        2. After downloading the plugin, you need to find the tinymce folder in node_modules, copy the skins folder inside and put it in the public folder of the vue project

   

        3. You also need to download a language pack to translate the plug-in into Chinese. The download address is as follows

   Official website address: https://www.tiny.cloud/get-tiny/language-packages/     

    Find zh-ch to download, as follows:

        After that, place the downloaded language pack in the public folder of vue, and then introduce it in the code. The name of the language pack I downloaded is zh-Hans, which may be different from others, but the final effect is the same Same, just import directly according to the file name

        The following is the code, some plug-ins and some basic configurations introduced

<template>
  <div class="editor_wraper">
    <editor :init="tinymceInit" v-model="content"> </editor>
  </div>
</template>

<script>
import tinymce from "tinymce";
import Editor from "@tinymce/tinymce-vue";
import "tinymce/themes/silver";
import {
  toolbar,
  fontsizeFormats,
  fontFormats,
  lineheightFormats,
} from "@/utils/tinymceConfig";
export default {
  data() {
    return {
      content: "",
      tinymceInit: {
        language_url: "tinymce/langs/zh-Hans.js", //引入语言包文件
        language: "zh-Hans", //语言类型
        skin_url: "tinymce/skins/ui/oxide", //皮肤:浅色
        quickbars_image_toolbar: "", // 选中媒体文件时的弹框
        // skin_url: '/tinymce/skins/ui/oxide-dark',//皮肤:暗色
        toolbar: toolbar, //工具栏配置,设为false则隐藏
        menubar: false, //菜单栏配置,设为false则隐藏,不配置则默认显示全部菜单,也可自定义配置--查看 http://tinymce.ax-z.cn/configure/editor-appearance.php --搜索“自定义菜单”
        height: 500, // 富文本高度
        model: 'dom', // 是否可拉伸富文本框
        fontsize_formats: fontsizeFormats, //字体大小
        font_formats: fontFormats, //字体样式
        lineheight_formats: lineheightFormats, //行高配置,也可配置成"12px 14px 16px 20px"这种形式
        placeholder: "在这里输入文字",
        branding: false, //tiny技术支持信息是否显示
        resize: "both", //编辑器宽高是否可变,false-否,true-高可变,'both'-宽高均可,注意引号
        statusbar: false,  //最下方的元素路径和字数统计那一栏是否显示
        paste_data_images: true, //图片是否可粘贴
        elementpath: false, //元素路径是否显示
      },
    };
  },
  components: { Editor },
};
</script>

        Here are some configurations in the tinymceConfig file introduced above

/**
 * @description: 工具栏配置
 * @return {*}
 */
export const toolbar = `
  undo redo restoredraft |
  removeformat|
  formatselect |
  subscript superscript |
  bold italic underline strikethrough link anchor |
  numlist bullist blockquote |
  alignleft aligncenter alignright alignjustify|
  quicklink searchreplace image|
  forecolor backcolor |
  fontselect fontsizeselect|
  outdent indent lineheight|`

/**
 * @description: 字体大小设置
 * @return {*}
 */
export const fontsizeFormats = `12px 14px 16px 18px 20px 22px 24px 28px 32px 36px 48px 56px 72px`
/**
 * @description: 字体设置
 * @return {*}
 */
export const fontFormats = `微软雅黑=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;`
/**
 * @description: 行高设置
 * @return {*}
 */
export const lineheightFormats = "0.5 0.8 1 1.2 1.5 1.75 2 2.5 3 4 5"

After configuring the above content, the page may display the following effect

2. Insert a specific title and abstract between the toolbar and the text

        The way to insert the title and abstract is to use the inline mode to achieve it, as follows I modified it based on the above code

       Note: If you configure toolbar_persist to true after enabling the inline mode, your tinymce still needs to be clicked to display the toolbar instead of a fixed display, it is likely that you did not delete the tinymce package when you deleted it through npm uninstall before. There are many tinymce packages in node_modules. At this time, you need to delete your entire node_modules, and then install it again. The pit of the personal test

<template>
  <div class="editor_wraper">
    <div id="mytoolbar"></div>
    <el-input
      class="titleStyle"
      v-model="defaultTitle"
      type="textarea"
      resize="none"
      :autosize="{ minRows: 1, maxRows: 3 }"
      placeholder="请在这里输入标题"
    ></el-input>
    <el-input
      class="abstractStyle"
      v-model="defaultAbstract"
      type="textarea"
      resize="none"
      :autosize="{ minRows: 1 }"
      placeholder="摘要(可选)"
    ></el-input>
    <editor :init="tinymceInit" v-model="content"> </editor>
  </div>
</template>

<script>
import tinymce from "tinymce";
import Editor from "@tinymce/tinymce-vue";
import "tinymce/themes/silver";
import {
  toolbar,
  fontsizeFormats,
  fontFormats,
  lineheightFormats,
} from "@/utils/tinymceConfig";
import "tinymce/icons/default"; // 方式工具栏的icon乱码
export default {
  data() {
    return {
      defaultTitle: "",
      defaultAbstract: "",
      content: "",
      tinymceInit: {
        language_url: "tinymce/langs/zh-Hans.js", //引入语言包文件
        language: "zh-Hans", //语言类型
        skin_url: "tinymce/skins/ui/oxide", //皮肤:浅色
        quickbars_image_toolbar: "", // 选中媒体文件时的弹框
        // skin_url: '/tinymce/skins/ui/oxide-dark',//皮肤:暗色
        toolbar: toolbar, //工具栏配置,设为false则隐藏
        menubar: false, //菜单栏配置,设为false则隐藏,不配置则默认显示全部菜单,也可自定义配置--查看 http://tinymce.ax-z.cn/configure/editor-appearance.php --搜索“自定义菜单”
        height: 500, // 富文本高度
        model: 'dom', // 是否可拉伸富文本框
        fontsize_formats: fontsizeFormats, //字体大小
        font_formats: fontFormats, //字体样式
        lineheight_formats: lineheightFormats, //行高配置,也可配置成"12px 14px 16px 20px"这种形式
        placeholder: "在这里输入文字",
        branding: false, //tiny技术支持信息是否显示
        resize: "both", //编辑器宽高是否可变,false-否,true-高可变,'both'-宽高均可,注意引号
        statusbar: false,  //最下方的元素路径和字数统计那一栏是否显示
        paste_data_images: true, //图片是否可粘贴
        elementpath: false, //元素路径是否显示

        inline: true, //使用内联模式
        toolbar_persist: true, // 在内联模式中,工具栏是否自动显示和隐藏
        fixed_toolbar_container: "#mytoolbar", // 将工具栏显示在一个固定的html元素上
      },
    };
  },
  components: { Editor },
};
</script>

<style lang="scss">
.editor_wraper {
  width: 60%;
  height: 80vh;
  margin: 0 auto;
}
.mce-content-body{
  height: 100%;
  outline: none;
}
.titleStyle .el-textarea__inner {
  width: 100%;
  height: 56px;
  font-size: 24px;
  font-weight: 500;
  margin-top: 10px;
  padding-left: 0;
  border: none;
}
.abstractStyle .el-textarea__inner {
  font-size: 22px;
  font-weight: 500;
  color: #bbb;
  margin-top: 5px;
  padding-left: 0;
  border: none;
}
</style>

 After matching, the following effects can be displayed

 

3. Customize toolbar buttons to achieve specific functions

        There are three steps to create a custom button:

        1. Create a method in my tinymceConfig file

/**
 * @description: 自定义按钮
 * @param {*} editor
 * @return {*}
 */
export const customBtn = (editor) => {
  // 参数一:自定义名称,需要放置在工具栏中
  editor.ui.registry.addButton("customBtn", {
    icon: "brightness", // 显示的图标
    tooltip: '自定义按钮', // 提示文字
    onAction: function () {
      console.log("点击了自定义按钮")
    }
  })
}

        2. Reference it in the tinymce configuration

        3. Place the custom name you declared in addButton in the toolbar

      

        Finally, the created button will be displayed.


        Note: If you want to modify the icon, you can refer to some icon addresses         given on the official website : https://www.tiny.cloud/docs/tinymce/6/editor-icon-identifiers/         

 4. Remove the network upload function when uploading pictures

        The so-called removal means that I re-customized a picture upload by myself. I did not use the picture upload in tinymce. The custom button can be created according to the above method. Here I only write how to upload pictures.

/**
 * @description: 自定义图片上传
 * @param {*} editor
 * @return {*}
 */
export const imageUpload = (editor) => {
  editor.ui.registry.addButton("imageUpload", {
    icon: "image",
    tooltip: '上传图片',
    onAction: function () {
      var input = document.createElement("input");
      input.setAttribute("type", "file");
      input.setAttribute("accept", "image/*");
      input.onchange = function () {
        var file = this.files[0];
        if (file.size / 1024 / 1024 > 20) {
          failure("上传失败,图片大小请控制在 20M 以内");
        } else {
          let formData = new FormData();
          formData.append("picture", file);
          formData.append("action", "add");
          // 上传后的逻辑
          uploadImage({ formData }).then((res) => {
            var reader = new FileReader();
            reader.onload = function () {
              var id = "blobid" + new Date().getTime();
              var blobCache = tinymce.activeEditor.editorUpload.blobCache;
              var base64 = reader.result.split(",")[1];
              var blobInfo = blobCache.create(id, file, base64);
              blobCache.add(blobInfo);
              // 将图片插入到文本中
              editor.insertContent(`<img src="${blobInfo.blobUri()}"/>`);
            };
            reader.readAsDataURL(file);
          }).catch(() => {
            failure("上传出错,服务器开小差了");
          });
        }
      };
      // 触发上传
      input.click();
    },
  });
}

5. The pasted pictures can be uploaded by default

        To use the paste and copy function, you need to introduce the paste plugin directly on the page

         import "tinymce/plugins/paste"; Just import it, and then add plugins in the configuration for configuration

 Then monitor the copied content through paste_postprocess in the configuration, and write the pasted logic in paste_postprocess

<script>
import tinymce from "tinymce";
import Editor from "@tinymce/tinymce-vue";
import "tinymce/themes/silver";
import {
  toolbar,
  fontsizeFormats,
  fontFormats,
  lineheightFormats,
  customBtn,
  imageUpload,
} from "@/utils/tinymceConfig";
import "tinymce/plugins/paste"; // 复制粘贴的插件
import "tinymce/icons/default"; // 方式工具栏的icon乱码
export default {
  data() {
    return {
      defaultTitle: "",
      defaultAbstract: "",
      content: "",
      tinymceInit: {
        language_url: "tinymce/langs/zh-Hans.js", //引入语言包文件
        language: "zh-Hans", //语言类型
        skin_url: "tinymce/skins/ui/oxide", //皮肤:浅色
        quickbars_image_toolbar: "", // 选中媒体文件时的弹框
        plugins: "paste", //插件配置
        // skin_url: '/tinymce/skins/ui/oxide-dark',//皮肤:暗色
        toolbar: toolbar, //工具栏配置,设为false则隐藏
        menubar: false, //菜单栏配置,设为false则隐藏,不配置则默认显示全部菜单,也可自定义配置--查看 http://tinymce.ax-z.cn/configure/editor-appearance.php --搜索“自定义菜单”
        height: 500, // 富文本高度
        model: "dom", // 是否可拉伸富文本框
        fontsize_formats: fontsizeFormats, //字体大小
        font_formats: fontFormats, //字体样式
        lineheight_formats: lineheightFormats, //行高配置,也可配置成"12px 14px 16px 20px"这种形式
        placeholder: "在这里输入文字",
        branding: false, //tiny技术支持信息是否显示
        resize: "both", //编辑器宽高是否可变,false-否,true-高可变,'both'-宽高均可,注意引号
        statusbar: false, //最下方的元素路径和字数统计那一栏是否显示
        paste_data_images: true, //图片是否可粘贴
        elementpath: false, //元素路径是否显示

        inline: true, // 使用内联模式
        toolbar_persist: true, // 在内联模式中,工具栏是否自动显示和隐藏
        fixed_toolbar_container: "#mytoolbar", // 将工具栏显示在一个固定的html元素上
        // 粘贴内容时的回调
        paste_postprocess: (plugin, args) => {
          this.$nextTick(() => {
            // 获取当前编辑器标签
            const doc = tinymce.activeEditor.getBody();
            // 循序所有标签
            doc.childNodes.forEach(async (item) => {
              const tag = item.firstChild; // 获取当前标签下的第一个标签
              // 判断当前标签或当前标签下面的第一个标签是否是一个img
              if (item.localName === "img" || tag.localName === "img") {
                const src =
                  item.localName === "img"
                    ? item.getAttribute("src")
                    : tag.getAttribute("src");
                // 如果是则拿到当前标签的图片地址,传递给后端,进行保存
                const { data } = await uploadImgByUrl({ url: src });
                // 拼接后端保存后的图片地址
                const url = process.env.VUE_APP_BASE_API + data;
                // 然后将新地址重新赋值给img标签
                item.localName === "img"
                  ? item.setAttribute("src", url)
                  : tag.setAttribute("src", url);
              }
            });
          });
        },
        // 自定义工具栏配置
        setup: function (editor) {
          // 自定义图片上传功能
          customBtn(editor);
          // 图片上传
          imageUpload(editor);
        },
      },
    };
  },
  components: { Editor },
};
</script>

6. Add watermark function to pictures

        I also created a custom button to realize the function of adding watermark. Adding watermark here is to add watermark to all the pictures in the article. If you have individual needs, you can modify it by yourself. Create a custom button to see the above way

        If there are too many pictures, it may take a little longer to add the watermark. It is recommended to add a loading state

/**
 * @description: 添加图片水印
 * @param {*} editor
 * @return {*}
 */
export const imageWatermark = (editor) => {
  editor.ui.registry.addButton("imageWatermark", {
    icon: "edit-image",
    tooltip: '添加图片水印',
    onAction: function () {
      const doc = tinymce.activeEditor.getBody()
      doc.childNodes.forEach(item => {
        const tag = item.firstChild
        // 单独修改img标签
        if (item.localName === "img" || tag.localName === "img") {
          editImages(tag)
        }
      })
    }
  })
}

/**
 * @description: 给图片添加水印
 * @param {*} child
 * @return {*}
 */
const editImages = (child) => {
  const src = child.getAttribute("src")
  var image = new Image();
  image.crossOrigin = 'anonymous';
  image.src = src;
  image.onload = async () => {
    // 创建canvas,并将创建的img绘制成canvas
    const canvas = document.createElement('canvas')
    canvas.width = child.width
    canvas.height = child.height
    const ctx = canvas.getContext('2d')
    ctx.drawImage(image, 0, 0)
    ctx.textAlign = "left"
    ctx.textBaseline = "top"
    ctx.font = "18px Microsoft Yahei"
    ctx.fillStyle = "rgba(255, 255, 255, 0.5)"
    ctx.rotate((Math.PI / 180) * 15)
    for (let i = 0; i < child.height / 120; i++) {
      for (let j = 0; j < child.width / 50; j++) {
        ctx.fillText("这是水印", i * 200, j * 100, child.width)
      }
    }
    const base64Url = canvas.toDataURL()
    setTimeout(() => {
      // 将添加好水印的图片重新插入到富文本中
      child.setAttribute("src", base64Url)
    }, 5000)
  }
}

7. Realize one-key typesetting

The one-click typesetting method also creates a custom button. The implementation method is basically the same, that is, after obtaining the dom node, the corresponding node label is judged, and then different styles are added to the corresponding label.

/**
 * @description: 一键排版
 * @param {*} editor
 * @return {*}
 */
const objLabel = {
  "h1": "title",
  "h2": "title",
  "h3": "title",
  "p": "paragraph"
}
const objStyle = {
  title: {
    "font-family": "微软雅黑",
    "font-size": "22px"
  },
  paragraph: {
    "font-size": "16px",
    "color": "red"
  }
}
export const oneClickLayout = (editor) => {
  // 参数一:自定义名称,需要放置在工具栏中
  editor.ui.registry.addButton("oneClickLayout", {
    icon: "orientation", // 显示的图标
    tooltip: '一键布局', // 提示文字
    onAction: function () {
      const doc = tinymce.activeEditor.getBody()
      doc.childNodes.forEach(item => {
        // 获取需要修改的标签
        const text = objLabel[item.localName]
        if (text) {
          // 找到对应样式循环进行配置
          for (let v in objStyle[text]) {
            item.style[v] = objStyle[text][v]
          }
        }
      })
    }
  })
}

At this point, all the functions have been completed, and the code of the entire function is attached below

<template>
  <div class="editor_wraper">
    <div id="mytoolbar"></div>
    <el-input
      class="titleStyle"
      v-model="defaultTitle"
      type="textarea"
      resize="none"
      :autosize="{ minRows: 1, maxRows: 3 }"
      placeholder="请在这里输入标题"
    ></el-input>
    <el-input
      class="abstractStyle"
      v-model="defaultAbstract"
      type="textarea"
      resize="none"
      :autosize="{ minRows: 1 }"
      placeholder="摘要(可选)"
    ></el-input>
    <editor :init="tinymceInit" v-model="content"> </editor>
  </div>
</template>

<script>
import tinymce from "tinymce";
import Editor from "@tinymce/tinymce-vue";
import "tinymce/themes/silver";
import {
  toolbar,
  fontsizeFormats,
  fontFormats,
  lineheightFormats,
  customBtn,
  imageUpload,
  oneClickLayout
} from "@/utils/tinymceConfig";
import "tinymce/plugins/paste";
import "tinymce/icons/default"; // 方式工具栏的icon乱码
export default {
  data() {
    return {
      defaultTitle: "",
      defaultAbstract: "",
      content: "",
      tinymceInit: {
        language_url: "tinymce/langs/zh-Hans.js", //引入语言包文件
        language: "zh-Hans", //语言类型
        skin_url: "tinymce/skins/ui/oxide", //皮肤:浅色
        quickbars_image_toolbar: "", // 选中媒体文件时的弹框
        plugins: "paste", //插件配置
        // skin_url: '/tinymce/skins/ui/oxide-dark',//皮肤:暗色
        toolbar: toolbar, //工具栏配置,设为false则隐藏
        menubar: false, //菜单栏配置,设为false则隐藏,不配置则默认显示全部菜单,也可自定义配置--查看 http://tinymce.ax-z.cn/configure/editor-appearance.php --搜索“自定义菜单”
        height: 500, // 富文本高度
        model: "dom", // 是否可拉伸富文本框
        fontsize_formats: fontsizeFormats, //字体大小
        font_formats: fontFormats, //字体样式
        lineheight_formats: lineheightFormats, //行高配置,也可配置成"12px 14px 16px 20px"这种形式
        placeholder: "在这里输入文字",
        branding: false, //tiny技术支持信息是否显示
        resize: "both", //编辑器宽高是否可变,false-否,true-高可变,'both'-宽高均可,注意引号
        statusbar: false, //最下方的元素路径和字数统计那一栏是否显示
        paste_data_images: true, //图片是否可粘贴
        elementpath: false, //元素路径是否显示

        inline: true, // 使用内联模式
        toolbar_persist: true, // 在内联模式中,工具栏是否自动显示和隐藏
        fixed_toolbar_container: "#mytoolbar", // 将工具栏显示在一个固定的html元素上
        // 粘贴内容时的回调
        paste_postprocess: (plugin, args) => {
          this.$nextTick(() => {
            // 获取当前编辑器标签
            const doc = tinymce.activeEditor.getBody();
            // 循序所有标签
            doc.childNodes.forEach(async (item) => {
              const tag = item.firstChild; // 获取当前标签下的第一个标签
              // 判断当前标签或当前标签下面的第一个标签是否是一个img
              if (item.localName === "img" || tag.localName === "img") {
                const src =
                  item.localName === "img"
                    ? item.getAttribute("src")
                    : tag.getAttribute("src");
                // 如果是则拿到当前标签的图片地址,传递给后端,进行保存
                const { data } = await uploadImgByUrl({ url: src });
                // 拼接后端保存后的图片地址
                const url = process.env.VUE_APP_BASE_API + data;
                // 然后将新地址重新赋值给img标签
                item.localName === "img"
                  ? item.setAttribute("src", url)
                  : tag.setAttribute("src", url);
              }
            });
          });
        },
        // 自定义工具栏配置
        setup: function (editor) {
          // 自定义图片上传功能
          customBtn(editor);
          // 图片上传
          imageUpload(editor);
          // 一键布局
          oneClickLayout(editor)
        },
      },
    };
  },
  components: { Editor },
};
</script>

<style lang="scss">
.editor_wraper {
  width: 60%;
  height: 80vh;
  margin: 0 auto;
}
.mce-content-body {
  height: 100%;
  outline: none;
}
.titleStyle .el-textarea__inner {
  width: 100%;
  height: 56px;
  font-size: 24px;
  font-weight: 500;
  margin-top: 10px;
  padding-left: 0;
  border: none;
}
.abstractStyle .el-textarea__inner {
  font-size: 22px;
  font-weight: 500;
  color: #bbb;
  margin-top: 5px;
  padding-left: 0;
  border: none;
}
</style>

Here is the code of the tinymceConfig file


/**
 * @description: 工具栏配置
 * @return {*}
 */
export const toolbar = `
  customBtn imageUpload oneClickLayout|
  undo redo restoredraft |
  removeformat|
  formatselect |
  subscript superscript |
  bold italic underline strikethrough link anchor |
  numlist bullist blockquote |
  alignleft aligncenter alignright alignjustify|
  quicklink searchreplace image|
  forecolor backcolor |
  fontselect fontsizeselect|
  outdent indent lineheight|`

/**
 * @description: 字体大小设置
 * @return {*}
 */
export const fontsizeFormats = `12px 14px 16px 18px 20px 22px 24px 28px 32px 36px 48px 56px 72px`
/**
 * @description: 字体设置
 * @return {*}
 */
export const fontFormats = `微软雅黑=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;`
/**
 * @description: 行高设置
 * @return {*}
 */
export const lineheightFormats = "0.5 0.8 1 1.2 1.5 1.75 2 2.5 3 4 5"

/**
 * @description: 自定义按钮
 * @param {*} editor
 * @return {*}
 */
export const customBtn = (editor) => {
  // 参数一:自定义名称,需要放置在工具栏中
  editor.ui.registry.addButton("customBtn", {
    icon: "brightness", // 显示的图标
    tooltip: '自定义按钮', // 提示文字
    onAction: function () {
      console.log("点击了自定义按钮")
    }
  })
}

/**
 * @description: 自定义图片上传
 * @param {*} editor
 * @return {*}
 */
export const imageUpload = (editor) => {
  editor.ui.registry.addButton("imageUpload", {
    icon: "image",
    tooltip: '上传图片',
    onAction: function () {
      var input = document.createElement("input");
      input.setAttribute("type", "file");
      input.setAttribute("accept", "image/*");
      input.onchange = function () {
        var file = this.files[0];
        if (file.size / 1024 / 1024 > 20) {
          failure("上传失败,图片大小请控制在 20M 以内");
        } else {
          let formData = new FormData();
          formData.append("picture", file);
          formData.append("action", "add");
          // 上传后的逻辑
          uploadImage({ formData }).then((res) => {
            var reader = new FileReader();
            reader.onload = function () {
              var id = "blobid" + new Date().getTime();
              var blobCache = tinymce.activeEditor.editorUpload.blobCache;
              var base64 = reader.result.split(",")[1];
              var blobInfo = blobCache.create(id, file, base64);
              blobCache.add(blobInfo);
              // 将图片插入到文本中
              editor.insertContent(`<img src="${blobInfo.blobUri()}"/>`);
            };
            reader.readAsDataURL(file);
          }).catch(() => {
            failure("上传出错,服务器开小差了");
          });
        }
      };
      // 触发上传
      input.click();
    },
  });
}
/**
 * @description: 一键排版
 * @param {*} editor
 * @return {*}
 */
const objLabel = {
  "h1": "title",
  "h2": "title",
  "h3": "title",
  "p": "paragraph"
}
const objStyle = {
  title: {
    "font-family": "微软雅黑",
    "font-size": "22px"
  },
  paragraph: {
    "font-size": "16px",
    "color": "red"
  }
}
export const oneClickLayout = (editor) => {
  // 参数一:自定义名称,需要放置在工具栏中
  editor.ui.registry.addButton("oneClickLayout", {
    icon: "orientation", // 显示的图标
    tooltip: '一键布局', // 提示文字
    onAction: function () {
      const doc = tinymce.activeEditor.getBody()
      doc.childNodes.forEach(item => {
        // 获取需要修改的标签
        const text = objLabel[item.localName]
        if (text) {
          // 找到对应样式循环进行配置
          for (let v in objStyle[text]) {
            item.style[v] = objStyle[text][v]
          }
        }
      })
    }
  })
}

/**
 * @description: 添加图片水印
 * @param {*} editor
 * @return {*}
 */
export const imageWatermark = (editor) => {
  editor.ui.registry.addButton("imageWatermark", {
    icon: "edit-image",
    tooltip: '添加图片水印',
    onAction: function () {
      const doc = tinymce.activeEditor.getBody()
      doc.childNodes.forEach(item => {
        const tag = item.firstChild
        // 单独修改img标签
        if (item.localName === "img" || tag.localName === "img") {
          editImages(tag)
        }
      })
    }
  })
}
/**
 * @description: 给图片添加水印
 * @param {*} child
 * @return {*}
 */
const editImages = (child) => {
  const src = child.getAttribute("src")
  var image = new Image();
  image.crossOrigin = 'anonymous';
  image.src = src;
  image.onload = async () => {
    // 创建canvas,并将创建的img绘制成canvas
    const canvas = document.createElement('canvas')
    canvas.width = child.width
    canvas.height = child.height
    const ctx = canvas.getContext('2d')
    ctx.drawImage(image, 0, 0)
    ctx.textAlign = "left"
    ctx.textBaseline = "top"
    ctx.font = "18px Microsoft Yahei"
    ctx.fillStyle = "rgba(255, 255, 255, 0.5)"
    ctx.rotate((Math.PI / 180) * 15)
    for (let i = 0; i < child.height / 120; i++) {
      for (let j = 0; j < child.width / 50; j++) {
        ctx.fillText("这是水印", i * 200, j * 100, child.width)
      }
    }
    const base64Url = canvas.toDataURL()
    setTimeout(() => {
      child.setAttribute("src", base64Url)
    }, 5000)
  }
}

This is some experience during the use of tinymce, and it took a long time to realize it. If you have any questions, please discuss with us

Guess you like

Origin blog.csdn.net/qq_39215166/article/details/130688837