vue2 uses tinymce rich text editor-image upload, paste image upload to the server

1. Install the tinymce rich text editor plug-in
npm i tinymce
npm i @tinymce/tinymce-vue

2. Create the Editor.js file to encapsulate the component for use

<template>
  <div class="tinymce-editor">
    <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 Api from "@/api/typical/typical"; //Introduce the interface
import Vue from "vue";
import 'tinymce/skins/ui/oxide/skin.css'
import 'tinymce/themes/silver/theme'
The following is the toolbar plug-in. Check whether your project requirements are commented out.
import 'tinymce/plugins/image' // Image plug-in
// import 'tinymce/plugins/media' // video plug-in
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/preview";
import "tinymce/plugins/code";
import "tinymce/plugins/link";
import "tinymce/plugins/advlist";
import "tinymce/plugins/codesample";
import "tinymce/plugins/hr";
import "tinymce/plugins/fullscreen";
import "tinymce/plugins/textpattern";
import "tinymce/plugins/searchreplace";
import "tinymce/plugins/autolink";
import "tinymce/plugins/directionality";
import "tinymce/plugins/visualblocks";
import "tinymce/plugins/visualchars";
import "tinymce/plugins/template";
import "tinymce/plugins/charmap";
import "tinymce/plugins/nonbreaking";
import "tinymce/plugins/insertdatetime";
import "tinymce/plugins/imagetools";
import "tinymce/plugins/autosave";
import "tinymce/plugins/autoresize";
import '../../../public/tinymce/langs/zh_CN.js'//Chinese package Put the Chinese package in your own project address and modify it according to your own path
// tinymce.addI18n('zh_CN', lang); //Register Chinese language. If the configuration here does not work, it can be configured later.
  export default {<!-- -->
    name: 'TinymceEditor',
    components: {<!-- -->
      Editor
    },
    props: {<!-- -->
      value: {<!-- -->
        type: String,
        default: ''
      },
      disabled: {<!-- -->
        type: Boolean,
        default: false
      },
      plugins: {<!-- -->
        type: [String, Array],
        default: 'lists image media table wordcount fullscreen'
      },
      toolbar: {<!-- -->
        type: [String, Array],
        default: 'undo redo | formatselect | bold italic forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | lists image media table | removeformat | fullscreen'
      }
    },
    data () {<!-- -->
      return {<!-- -->
        init: {<!-- -->
          language: 'zh_CN',
          skin_url: '/static/tinymce/skins/ui/oxide',
          // skin_url: '/tinymce/skins/ui/oxide-dark',//dark color
          height: 300,
          plugins: this.plugins,
          toolbar: this.toolbar,
          external_plugins: {<!-- -->
            'powerpaste': '/tinymce/plugins/powerpaste/plugin.min.js' // words paste plug-in
          },
          branding: false,
          menubar: false,
          end_container_on_empty_block: true,
          powerpaste_word_import: 'merge',
          powerpaste_html_import: 'merge',
          powerpaste_allow_local_images: true,
          paste_data_images: true, // Allow word paste
          // Screenshot of the pasted image needs to be uploaded, otherwise it is a file stream (the image upload in the toolbar of this method is two methods. Write separately, this method is used when pasting images)
          urlconverter_callback: function(url, node, on_save, name) {<!-- -->
            if (node === 'img' & amp; & amp; url.startsWith('blob:') || url.startsWith('data:')) {<!-- -->
              // console.log('urlConverter:', url, 'node',node, on_save, name)
              tinymce.activeEditor & amp; & amp; tinymce.activeEditor.uploadImages()
            }
            return url;
          },
          // Here is the image upload processing function. This method uploads images to the toolbar. It needs to use the background upload interface to distinguish it from the above method.
          images_upload_handler: function (blobInfo, success, failure) {<!-- -->
            //base64 to local upload
            // This function mainly processes pictures in word and automatically completes the upload;
            // A function defined by yourself; in the callback, remember to call the success function and pass in the uploaded image address;
            // blobInfo.blob() gets the file object of the image;
            let formData = new FormData()
            formData.append('file', blobInfo.blob())
            Api.uploadFile(formData).then(res => {<!-- -->
              if (res.data.code == 0) {<!-- -->
                // Return path Vue.prototype.urlData + splicing
                success(Vue.prototype.urlData + res.data.filePath)
              }
            })
          },
        },
        myValue: this.value
      }
    },
    mounted () {<!-- -->
      tinymce.init({<!-- -->})
    },
    methods: {<!-- -->
      //Add related events, refer to the documentation for available events => https://github.com/tinymce/tinymce-vue => All available events
      // You can add any events you need
      onClick (e) {<!-- -->
        this.$emit('onClick', e, tinymce)
      },
      // You can add some of your own custom events, such as clearing content
      clear () {<!-- -->
        this.myValue = ''
      }
    },
    watch: {<!-- -->
      value (newValue) {<!-- -->
        this.myValue = newValue
      },
      myValue (newValue) {<!-- -->
        this.$emit('input', newValue)
      }
    },
    beforeDestroy () {<!-- -->
      tinymce.remove()
    }
  }
</script>

3. Chinese package (I put it in the public/tynymce/langs folder)

/* eslint-disable */
tinymce.addI18n('zh_CN',{<!-- -->
    "Redo": "Restore",
    "Undo": "Undo",
    "Cut": "Cut",
    "Copy": "Copy",
    "Paste": "Paste",
    "Select all": "Select all",
    "New document": "New document",
    "Ok": "OK",
    "Cancel": "Cancel",
    "Visual aids": "Gridlines",
    "Bold": "Bold",
    "Italic": "italic",
    "Underline": "underline",
    "Strikethrough": "Strikethrough",
    "Superscript": "Superscript",
    "Subscript": "subscript",
    "Clear formatting": "Clear formatting",
    "Align left": "Align left",
    "Align center": "center",
    "Align right": "Align right",
    "Justify": "Justify",
    "Bullet list": "Symbol list",
    "Numbered list": "Numbered list",
    "Decrease indent": "Decrease indent",
    "Increase indent": "Increase indent",
    "Close": "Close",
    "Formats": "formats",
    "Your browser doesn't support direct access to the clipboard. Please use the Ctrl + X\/C\/V keyboard shortcuts instead.": "The current browser does not support direct access to the clipboard. Please use the shortcuts Key Ctrl + X/C/V to copy and paste ",
    "Headers": "Titles",
    "Header 1": "Header 1",
    "Header 2": "Header 2",
    "Header 3": "Header 3",
    "Header 4": "Header 4",
    "Header 5": "Header 5",
    "Header 6": "Header 6",
    "Headings": "Titles",
    "Heading 1": "Title 1",
    "Heading 2": "Title 2",
    "Heading 3": "Title 3",
    "Heading 4": "Title 4",
    "Heading 5": "Title 5",
    "Heading 6": "Title 6",
    "Preformatted": "Preformatted",
    "Div": "Div block",
    "Pre": "Preformatted text",
    "Code": "code",
    "Paragraph": "Paragraph",
    "Blockquote": "Quote",
    "Inline": "Text",
    "Blocks": "blocks",
    "Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "Currently in plain text paste mode, click again to return to normal paste mode.",
    "Fonts": "Fonts",
    "Font Sizes": "Font Sizes",
    "Class": "Class",
    "Browse for an image": "Browse for an image",
    "OR": "or",
    "Drop an image here": "Drop an image file here",
    "Upload": "Upload",
    "Block": "block",
    "Align": "Align",
    "Default": "Default",
    "Circle": "Hollow Circle",
    "Disc": "solid circle",
    "Square": "square",
    "Lower Alpha": "Lowercase English letters",
    "Lower Greek": "Lower case Greek letters",
    "Lower Roman": "Lower Roman letters",
    "Upper Alpha": "uppercase English letters",
    "Upper Roman": "uppercase Roman letters",
    "Anchor...": "Anchor...",
    "Name": "Name",
    "Id": "id",
    "Id should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.": "Id should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores." ",
    "You have unsaved changes are you sure you want to navigate away?": "Your changes to the document have not been saved, are you sure you want to navigate away?",
    "Restore last draft": "Restore last draft",
    "Special characters...": "Special characters...",
    "Source code": "HTML source code",
    "Insert\/Edit code sample": "Insert/Edit code sample",
    "Language": "Language",
    "Code sample...": "Code sample...",
    "Color Picker": "Select Color",
    "R": "R",
    "G": "G",
    "B": "B",
    "Left to right": "From left to right",
    "Right to left": "From right to left",
    "Emoticons...": "Emoticons...",
    "Metadata and Document Properties": "Metadata and Document Properties",
    "Title": "Title",
    "Keywords": "Keywords",
    "Description": "Description",
    "Robots": "Robots",
    "Author": "Author",
    "Encoding": "Encoding",
    "Fullscreen": "Fullscreen",
    "Action": "Action",
    "Shortcut": "Shortcut",
    "Help": "Help",
    "Address": "Address",
    "Focus to menubar": "Move focus to menu bar",
    "Focus to toolbar": "Move focus to toolbar",
    "Focus to element path": "Move focus to element path",
    "Focus to contextual toolbar": "Move focus to contextual menu",
    "Insert link (if link plugin activated)": "Insert link (if link plugin activated)",
    "Save (if save plugin activated)": "Save (if save plugin activated)",
    "Find (if searchreplace plugin activated)": "Find (if searchreplace plugin activated)",
    "Plugins installed ({0}):": "Plugins installed ({0}):",
    "Premium plugins:": "Premium plugins:",
    "Learn more...": "Learn more...",
    "You are using {0}": "You are using {0}",
    "Plugins": "Plugins",
    "Handy Shortcuts": "Shortcut keys",
    "Horizontal line": "Horizontal dividing line",
    "Insert\/edit image": "Insert/Edit Image",
    "Image description": "Image description",
    "Source": "Address",
    "Dimensions": "size",
    "Constrain proportions": "Maintain aspect ratio",
    "General": "General",
    "Advanced": "Advanced",
    "Style": "Style",
    "Vertical space": "Vertical margin",
    "Horizontal space": "Horizontal margin",
    "Border": "border",
    "Insert image": "Insert image",
    "Image...": "Image...",
    "Image list": "Image list",
    "Rotate counterclockwise": "Rotate counterclockwise",
    "Rotate clockwise": "Rotate clockwise",
    "Flip vertically": "Flip vertically",
    "Flip horizontally": "Flip horizontally",
    "Edit image": "Edit image",
    "Image options": "Image options",
    "Zoom in": "Zoom in",
    "Zoom out": "Zoom out",
    "Crop": "Crop",
    "Resize": "Resize",
    "Orientation": "Direction",
    "Brightness": "Brightness",
    "Sharpen": "Sharpen",
    "Contrast": "Contrast",
    "Color levels": "Color levels",
    "Gamma": "Gamma value",
    "Invert": "Reverse",
    "Apply": "Apply",
    "Back": "Back",
    "Insert date\/time": "Insert date/time",
    "Date\/time": "Date/time",
    "Insert\/Edit Link": "Insert/Edit Link",
    "Insert\/edit link": "Insert/Edit link",
    "Text to display": "Display text",
    "Url": "Address",
    "Open link in...": "Open link in...",
    "Current window": "The current window is open",
    "None": "Open in current window/frame",
    "New window": "Open in new window",
    "Remove link": "Remove link",
    "Anchors": "anchors",
    "Link...": "Link...",
    "Paste or type a link": "Paste or type a link",
    "The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?": "The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?": "The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?",
    "The URL you entered seems to be an external link. Do you want to add the required http:\/\/ prefix?": "The URL you entered seems to be an external link. Do you want to add the required http:\/\/ prefix?": "The URL you entered seems to be an external link. Do you want to add the required http:\/\/ prefix?": //:Prefix?",
    "Link list": "Link list",
    "Insert video": "Insert video",
    "Insert\/edit video": "Insert/Edit Video",
    "Insert\/edit media": "Insert/Edit Media",
    "Alternative source": "Alternative source",
    "Alternative image URL": "Alternative resource address",
    "Media poster (Image URL)": "Cover (Image URL)",
    "Paste your embed code below:": "Paste your embed code below:",
    "Embed": "embedded",
    "Media...": "Multimedia...",
    "Nonbreaking space": "Nonbreaking space",
    "Page break": "Page break",
    "Paste as text": "Paste as text",
    "Preview": "Preview",
    "Print...": "Print...",
    "Save": "Save",
    "Find": "Find",
    "Replace with": "replace with",
    "Replace": "Replace",
    "Replace all": "Replace all",
    "Previous": "Previous",
    "Next": "Next",
    "Find and replace...": "Find and replace...",
    "Could not find the specified string.": "The search content was not found.",
    "Match case": "Case sensitive",
    "Find whole words only": "Whole words match",
    "Spell check": "Spell check",
    "Ignore": "ignore",
    "Ignore all": "Ignore all",
    "Finish": "Complete",
    "Add to Dictionary": "Add to Dictionary",
    "Insert table": "Insert table",
    "Table properties": "Table properties",
    "Delete table": "Delete table",
    "Cell": "cell",
    "Row": "row",
    "Column": "Column",
    "Cell properties": "Cell properties",
    "Merge cells": "Merge cells",
    "Split cell": "Split cell",
    "Insert row before": "Insert above",
    "Insert row after": "Insert row after",
    "Delete row": "Delete row",
    "Row properties": "Row properties",
    "Cut row": "Cut row",
    "Copy row": "Copy row",
    "Paste row before": "Paste above",
    "Paste row after": "Paste below",
    "Insert column before": "Insert on the left",
    "Insert column after": "Insert on the right",
    "Delete column": "Delete column",
    "Cols": "Columns",
    "Rows": "rows",
    "Width": "width",
    "Height": "High",
    "Cell spacing": "Cell spacing",
    "Cell padding": "Cell padding",
    "Show caption": "Show caption",
    "Left": "Align left",
    "Center": "center",
    "Right": "right aligned",
    "Cell type": "Cell type",
    "Scope": "scope",
    "Alignment": "Alignment",
    "H Align": "Horizontal Align",
    "V Align": "Vertical Align",
    "Top": "Align top",
    "Middle": "Vertically centered",
    "Bottom": "Align bottom",
    "Header cell": "Header cell",
    "Row group": "Row group",
    "Column group": "Column group",
    "Row type": "Row type",
    "Header": "Header",
    "Body": "Table body",
    "Footer": "Footer",
    "Border color": "Border color",
    "Insert template...": "Insert template...",
    "Templates": "Templates",
    "Template": "Template",
    "Text color": "Text color",
    "Background color": "Background color",
    "Custom...": "Custom...",
    "Custom color": "Custom color",
    "No color": "No",
    "Remove color": "Remove color",
    "Table of Contents": "Table of Contents",
    "Show blocks": "Show block borders",
    "Show invisible characters": "Show invisible characters",
    "Word count": "Word count",
    "Words: {0}": "Words: {0}",
    "{0} words": "{0} words",
    "File": "File",
    "Edit": "Edit",
    "Insert": "Insert",
    "View": "View",
    "Format": "format",
    "Table": "Table",
    "Tools": "Tools",
    "Powered by {0}": "Powered by {0}",
    "Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "Press ALT + F9 in the editing area to open the menu, press ALT + F10 to open the toolbar, press ALT + 0 to view help",
    "Image title": "Image title",
    "Border width": "Border width",
    "Border style": "Border style",
    "Error": "Error",
    "Warn": "Warning",
    "Valid": "valid",
    "To open the popup, press Shift + Enter": "This shortcut is soft return (insert<br>)",
    "Rich Text Area. Press ALT-0 for help.": "Editing area. Press Alt + 0 to open help",
    "System Font": "Default Font",
    "Failed to upload image: {0}": "Failed to upload image: {0}",
    "Failed to load plugin: {0} from url {1}": "Failed to load plugin: {0} - {1}",
    "Failed to load plugin url: {0}": "Failed to load plugin url: {0}",
    "Failed to initialize plugin: {0}": "Failed to initialize plugin: {0}",
    "example": "example",
    "Search": "Search",
    "All": "All",
    "Currency": "Currency",
    "Text": "Text",
    "Quotations": "Quotes",
    "Mathematical": "Mathematical operators",
    "Extended Latin": "Latin Extended",
    "Symbols": "Symbols",
    "Arrows": "arrows",
    "User Defined": "Customized",
    "dollar sign": "dollar sign",
    "currency sign": "currency",
    "euro-currency sign": "Euro",
    "colon sign": "colon",
    "cruzeiro sign": "cruzeiro coin",
    "french franc sign": "french franc",
    "lira sign": "lira",
    "mill sign": "mill",
    "naira sign": "naira",
    "peseta sign": "peseta",
    "rupee sign": "rupee",
    "won sign": "South Korean won",
    "new sheqel sign": "new sheqel",
    "dong sign": "Vietnamese Dong",
    "kip sign": "Laos kip",
    "tugrik sign": "tugrik",
    "drachma sign": "drachma",
    "german penny symbol": "German penny",
    "peso sign": "peso",
    "guarani sign": "Guarani",
    "austral sign": "Australian dollar",
    "hryvnia sign": "hryvnia",
    "cedi sign": "cedi",
    "livre tournois sign": "livrevere",
    "spesmilo sign": "The currency symbol of one thousand spesoj, this currency is not used",
    "tenge sign": "tenge",
    "indian rupee sign": "Indian rupee",
    "turkish lira sign": "Turkish lira",
    "nordic mark sign": "Nordic mark",
    "manat sign": "manat",
    "ruble sign": "ruble",
    "yen character": "yen",
    "yuan character": "RMB yuan",
    "yuan character, in hong kong and taiwan": "yuan's traditional Chinese character",
    "yen\/yuan character variant one": "元(uppercase)",
    "Loading emoticons...": "Loading emoticons...",
    "Could not load emoticons": "Can't load emoticons",
    "People": "Humanity",
    "Animals and Nature": "Animals and Nature",
    "Food and Drink": "Food and Drink",
    "Activity": "Activity",
    "Travel and Places": "Travel and Places",
    "Objects": "Objects",
    "Flags": "Flags",
    "Characters": "Number of words",
    "Characters (no spaces)": "Number of characters (no spaces)",
    "Error: Form submit field collision.": "Error: Form submit field collision.",
    "Error: No form element found.": "Error: No available form found.",
    "Update": "Update",
    "Color swatch": "Color swatch",
    "Turquoise": "turquoise",
    "Green": "green",
    "Blue": "blue",
    "Purple": "Purple",
    "Navy Blue": "Navy Blue",
    "Dark Turquoise": "Dark Turquoise",
    "Dark Green": "Dark Green",
    "Medium Blue": "Medium Blue",
    "Medium Purple": "Medium Purple",
    "Midnight Blue": "Midnight Blue",
    "Yellow": "yellow",
    "Orange": "orange",
    "Red": "red",
    "Light Gray": "Light Gray",
    "Gray": "Gray",
    "Dark Yellow": "Dark Yellow",
    "Dark Orange": "Dark Orange",
    "Dark Red": "Dark Red",
    "Medium Gray": "Medium Gray",
    "Dark Gray": "Dark Gray",
    "Black": "black",
    "White": "white",
    "Switch to or from fullscreen mode": "Switch to fullscreen mode",
    "Open help dialog": "Open help dialog",
    "history": "history",
    "styles": "styles",
    "formatting": "formatting",
    "alignment": "alignment",
    "indentation": "indentation",
    "permanent pen": "marker pen",
    "comments": "comments",
    "Anchor": "anchor",
    "Special character": "Special character",
    "Code sample": "Code sample",
    "Color": "Color",
    "Emoticons": "Emoticons",
    "Document properties": "Document properties",
    "Image": "Picture",
    "Insert link": "Insert link",
    "Target": "target",
    "Link": "Link",
    "Poster": "Cover",
    "Media": "Audio and Video",
    "Print": "Print",
    "Prev": "Previous",
    "Find and replace": "Find and replace",
    "Whole words": "Whole words",
    "Spellcheck": "Spellcheck",
    "Caption": "title",
    "Insert template": "Insert template",
    //The following is supplementary Chinese content by Mo Ruoqing
    "Code view": "code area",
    "Select...": "Select...",
    "Format Painter": "Format Painter",
    "No templates defined.": "No built-in templates",
    "Special character...": "Special character...",
    "Open link": "Open link",
    "None": "None",
    "Count": "Statistics",
    "Document": "Entire document",
    "Selection": "Selection",
    "Words": "Number of words",
    "{0} characters": "{0} characters",
    "Alternative source URL": "Alternative resource address",
    "Alternative description": "Alternative description",
    "Accessibility": "Accessibility",
    "Image is decorative": "For decoration only",
    //New in 5.6
    "Line height": "Line height",
    "Cut column": "Cut column",
    "Copy column": "Copy column",
    "Paste column before": "Paste to the front",
    "Paste column after": "Paste column after",
    "Copy column": "Copy column",
    //Text in the help window
    "Version": "Version",
    "Keyboard Navigation": "Keyboard Navigation",
    "Open popup menu for split buttons": "The function of this key combination is soft return (insert br)",
    });

4. Used in vue components

<template>
<div>
      <tinymce-editor
         :height="200"
         :value="nextImprovementPlan"
         @input="EditorChange($event)"
         :disabled="processStateDisabled"
       >
       </tinymce-editor>
     </div>
</template>
<script>
 //Introduce TinymceEditor
 import TinymceEditor from '@/components/Editor/TinymceEditor'
 export default {<!-- -->
 components:{<!-- -->
      TinymceEditor
    },
    data(){<!-- -->
    return {<!-- -->
    processStateDisabled:false, // disabled
    nextImprovementPlan:'', // Rich text value
    }
    },
    methods:{<!-- -->
    EditorChange(newValue){<!-- -->
console.log(newValue)
},
}
 }
 </script>

The focus of this record is on the method of uploading pictures. It is necessary to distinguish the method of uploading pictures in the toolbar and the pictures pasted in also need to be uploaded. The two methods need to be distinguished.
If there are any mistakes, I hope to correct them!

Reference article: http://blog.ncmem.com/wordpress/2023/10/17/vue2 using-tinymce rich text editor-image upload, paste image upload to/
Welcome to join the group to discuss