tinymce富文本编辑器

官方文档:https://www.tiny.cloud/docs/quick-start/
中文文档:http://tinymce.ax-z.cn/
支持vue、react、angular

react集成

命令

yarn add @tinymce/tinymce-react
yarn add tinymce

代码

import { useState, useEffect } from 'react'
import { Editor } from '@tinymce/tinymce-react'
import 'tinymce/tinymce'
import 'tinymce/models/dom'
import 'tinymce/icons/default'
import 'tinymce/themes/silver/theme'
// Skins
import './index.less'

// Plugins 组件根据init中调用情况自行加载
import 'tinymce/plugins/accordion'
import 'tinymce/plugins/charmap'
import 'tinymce/plugins/help'
import 'tinymce/plugins/media'
import 'tinymce/plugins/searchreplace'
import 'tinymce/plugins/advlist'
import 'tinymce/plugins/code'
import 'tinymce/plugins/image'
import 'tinymce/plugins/nonbreaking'
import 'tinymce/plugins/table'
import 'tinymce/plugins/anchor'
import 'tinymce/plugins/codesample'
import 'tinymce/plugins/importcss'
import 'tinymce/plugins/pagebreak'
import 'tinymce/plugins/template'
import 'tinymce/plugins/autolink'
import 'tinymce/plugins/directionality'
import 'tinymce/plugins/insertdatetime'
import 'tinymce/plugins/preview'
import 'tinymce/plugins/visualblocks'
import 'tinymce/plugins/autoresize'
import 'tinymce/plugins/emoticons'
import 'tinymce/plugins/link'
import 'tinymce/plugins/quickbars'
import 'tinymce/plugins/visualchars'
import 'tinymce/plugins/autosave'
import 'tinymce/plugins/fullscreen'
import 'tinymce/plugins/lists'
import 'tinymce/plugins/save'
import 'tinymce/plugins/wordcount'

import './langs/zh-Hans'

export default function RichEditor({ value, onChange }) {
  const [showEditor, setShowEditor] = useState(true)
  useEffect(() => {
    setShowEditor(false)
    setShowEditor(true)
  }, [value])
  const onEditorChange = (e) => {
    console.log(e)
    onChange(e)
  }
  const imagesUploadHandler = (blobInfo, progress) =>
    new Promise((resolve, reject) => {
      console.log(blobInfo, progress)
      resolve('1.jpg')
    })
  const config = {
    skin: false,
    content_css: false,
    height: 500,
    plugins: [
      'advlist',
      'anchor',
      'autolink',
      'help',
      'image',
      'link',
      'lists',
      'searchreplace',
      'table',
      'wordcount',
      'charmap',
      'preview',
      'anchor',
      'visualblocks',
      'code',
      'fullscreen',
      'insertdatetime',
      'media',
      'code',
      'codesample',
    ],
    toolbar:
      'undo redo | formatselect | bold italic backcolor |  alignleft aligncenter alignright alignjustify |bullist numlist outdent indent | removeformat |image|codesample|code|preview|fullscreen | help',
    menu: {
      file: { title: '文件', items: 'newdocument restoredraft | preview | print ' },
      edit: { title: 'Edit', items: 'undo redo | cut copy paste | selectall | searchreplace' },
      view: {
        title: 'View',
        items: 'code | visualaid visualchars visualblocks | spellchecker | preview fullscreen',
      },
      insert: {
        title: 'Insert',
        items:
          'image link media template codesample inserttable | charmap emoticons hr | pagebreak nonbreaking anchor toc | insertdatetime',
      },
      format: {
        title: 'Format',
        items:
          'bold italic underline strikethrough superscript subscript codeformat | formats blockformats fontformats fontsizes align | forecolor backcolor | removeformat',
      },
      tools: { title: 'Tools', items: 'spellchecker spellcheckerlanguage | code wordcount' },
      table: { title: 'Table', items: 'inserttable | cell row column | tableprops deletetable' },
      favs: {
        title: 'My Favorites',
        items: 'code visualaid | searchreplace | spellchecker | emoticons',
      },
    },
    menubar: 'file edit view insert format tools table favs',
    codesample_languages: [
      { text: 'HTML/XML', value: 'markup' },
      { text: 'JavaScript', value: 'javascript' },
      { text: 'CSS', value: 'css' },
      { text: 'PHP', value: 'php' },
      { text: 'Ruby', value: 'ruby' },
      { text: 'Python', value: 'python' },
      { text: 'Java', value: 'java' },
      { text: 'C', value: 'c' },
      { text: 'C#', value: 'csharp' },
      { text: 'C++', value: 'cpp' },
      { text: 'Scala', value: 'scala' },
    ],
    promotion: false, //阻止更新提示
    language: 'zh-Hans',
    image_uploadtab: true,
    images_upload_handler: imagesUploadHandler,
  }
  return (
    <>
      {showEditor && (
        <Editor
          initialValue={value}
          init={config}
          // tinymceScriptSrc="./1/tinymce.min.js"
          onEditorChange={onEditorChange}
        />
      )}
    </>
  )
}

样式文件

index.less
@import '~tinymce/skins/ui/oxide/skin.min.css';
@import '~tinymce/skins/ui/oxide/content.inline.min.css';

.tox-statusbar__branding {
  display: none;
}

使用组件

import { debounce } from 'lodash'

  const onChange = debounce((value) => {
    record.illustrate = value
    save(record)
  }, 1000)

<RichEditor value={record.illustrate} onChange={onChange} />