如何在 React 中实现 TinyMCE 到 Shared Textarea 和 Return 它的更新状态?

How to implement TinyMCE to Shared Textarea and Return its Updated State in React?

首先,我正在尝试将 tinyMCE 实现到来自 react-bootstrap 的组件。

所述组件是'dynamic'。它可以是我想要的任何类型的输入,但是当我尝试将它用作带有 tinyMCE 的文本区域时,状态不会 return 来自所述输入的任何数据并且我的数据库更新失败(通过艰难的方式学习)。

我使用它的第一个组件叫做 Edit.js。此输入应将新值存储在 producerData 上,但仅当我不初始化 tinyMCE 时才这样做。

const handleChange = (name) => (e) => {
  setIsBlocking(e.target.value.length > 0)
  setProducerData({ ...producerData, [name]: e.target.value })
};
<FormInput
  id={`text`}
  name={`text`}
  asType={`textarea`}
  handleChange={handleChange('text')}
  value={text}
  plugins={`toolbar`}
/>

话虽如此,这里是FormInput组件。我之前提到过它可以工作,但不一定与 tinyMCE 一起使用(这就是我目前评论它的原因),这正是我需要的:

import React from 'react'
// HELPERS
import { useScript } from '../../helpers/utilities'
// TINYMCE
import Form from 'react-bootstrap/Form'

const FormInput = ({
  id = ``,
  name = ``,
  type = ``,
  asType = ``,
  placeholder = `Write here...`,
  value = ``,
  handleChange,
  plugins = ``,
  classStr = ``,
  required = false,
  disabled = false,
  ariaLabel = ``,
  ariaDescribedby = ``,
  autoComplete = ``,
  children,
}) => {
  // useScript(
  //   'tinyMCE',
  //   `https://cdnjs.cloudflare.com/ajax/libs/tinymce/5.6.2/tinymce.min.js`,
  //   'origin',
  //   'head',
  //   false
  // );

  // if (asType === `textarea`) {
  //   window?.tinymce?.init({
  //     selector: `textarea#${id}`,
  //     // skin: `bootstrap`,
  //     branding: false,
  //     height: 300,
  //     plugins: `toc pagebreak charmap textpattern imagetools ${plugins}`,
  //   });
  // }

  return (
    <Form.Control
      {...{
        ...(id && { id: id }),
        ...(name && { name: name }),
        ...(type && { type: type }),
        ...(asType && { as: asType }),
        ...(placeholder && { placeholder: placeholder }),
        ...(handleChange && { onChange: handleChange }),
        ...(value && { value: value }),
        ...(classStr && { className: classStr }),
        ...(required && { required: required }),
        ...(disabled && { disabled: disabled }),
        ...(ariaLabel && `aria-label=${ariaLabel}`),
        ...(ariaDescribedby && `aria-describedby=${ariaDescribedby}`),
        ...(autoComplete && { autoComplete: autoComplete }),
      }}
    >
      {children && children}
    </Form.Control>
  )
}

export default FormInput

再一次,如果我没有很好地解释自己:上面的代码本身可以工作,但我希望它与 TinyMCE 一起工作

这里有人用过react-bootstrap和tinyMCE吗?谢谢!

最后这就是我的结局:

import React from 'react';
import 'tinymce/tinymce';
import 'tinymce/icons/default';
import 'tinymce/themes/silver';
import 'tinymce/plugins/paste';
import 'tinymce/plugins/link';
import 'tinymce/plugins/image';
import 'tinymce/plugins/table';
import 'tinymce/skins/ui/oxide/skin.min.css';
import 'tinymce/skins/ui/oxide/content.min.css';
import 'tinymce/skins/content/default/content.min.css';
import { Editor } from '@tinymce/tinymce-react';
import ReactHtmlParser from 'react-html-parser';
// HELPERS
import { useScript } from '../../helpers/utilities';

const FormInput = ({
  id = ``,
  name = ``,
  value = ``,
  handleChange,
  plugins = ``,
  isRequired = false
}) => {
  useScript(
    'tinyMCE',
    `https://cdnjs.cloudflare.com/ajax/libs/tinymce/5.6.2/tinymce.min.js`,
    'origin',
    'head',
    false
  );

  const parseEditorData = (content, editor) => {
    //content is the current value of the text editor
    // editor is an object that holds the html element that in this case is the text area where the name prop will be stored.
    const { targetElm } = editor;
    // This name value references the prop that you pass as textAreaName (content in your case)
    const { name } = targetElm;

    // This function returns an object that your handle change can parse correctly
    return {
      target: {
        name,
        value: content
      }
    };
  };

  return (
    <Editor
      apiKey={process.env.TINIYMCE_APIKEY}
      textareaName={name}
      initialValue={`${ReactHtmlParser(value)}`}
      init={{
        selector: `textarea#${id}`,
        skin: `bootstrap`,
        branding: false,
        height: 300,
        plugins: `image link advcode media powerpaste codesample preview wordcount visualchars toc pagebreak charmap textpattern imagetools ${plugins}`,
        autoresize_bottom_margin: 50,
        textpattern_patterns: [
          { start: '*', end: '*', format: 'italic' },
          { start: '**', end: '**', format: 'bold' },
          { start: '#', format: 'h1' },
          { start: '##', format: 'h2' },
          { start: '###', format: 'h3' },
          { start: '####', format: 'h4' },
          { start: '#####', format: 'h5' },
          { start: '######', format: 'h6' },
          { start: '1. ', cmd: 'InsertOrderedList' },
          { start: '* ', cmd: 'InsertUnorderedList' },
          { start: '- ', cmd: 'InsertUnorderedList' }
        ]
      }}
      onChange={(content, editor) =>
        handleChange(parseEditorData(content.level.content, editor))
      }
      outputFormat={`text`}
      required={isRequired}
    />
  );
};

export default FormInput;

用法:

import TinyMCE from '../../../layout/TinyMCE';
<TinyMCE
  id={`text`}
  name={`text`}
  handleChange={handleChange('text')}
  value={text}
  plugins={`toolbar`}
  isRequired={true}
/>