react富文本編輯器

react-draft-wysiwyg
wangeditor
slatejs
re-editor

Unknown DraftEntity key: null. 插入圖片,再輸入中文會報錯,下面方法可以解決,但是會產(chǎn)生iframe插入會產(chǎn)生問題,??,待解決


  function myBlockRenderer(contentBlock) {
    const type = contentBlock.getType();

    // 圖片類型轉(zhuǎn)換為mediaComponent
    if (type === 'atomic') {
      return {
        component: MediaComponent,
        editable: false,
        props: {
          foo: 'bar',
        },
      };
    }
  }

  class MediaComponent extends React.Component {
    render() {
      const { block, contentState } = this.props;
      const { foo } = this.props.blockProps;
      const data = contentState.getEntity(block.getEntityAt(0)).getData();
      

      const emptyHtml = ' ';
      return (
        <div>
          {emptyHtml}
          <img
            src={data.src}
            alt={data.alt || ''}
            style={{height: data.height || 'auto', width: data.width || 'auto'}}
          />
        </div>
      );
    }
  }
 <Editor blockRendererFn={myBlockRenderer} />

下面是富文本編輯器react-draft-wysiwyg的例子

引入

import { Editor } from 'react-draft-wysiwyg';
import draftToHtml from 'draftjs-to-html';
import { EditorState, convertToRaw, ContentState } from 'draft-js';
// css需要單獨引入
import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css';  
 <Editor
                editorState={editorContent}
                wrapperClassName={styles['demo-wrapper']}
                editorClassName={styles['demo-editor']}
                toolbarClassName={styles['toolbar-class']}
                placeholder="請輸文章內(nèi)容"
                localization={{
                  locale: 'zh',
                }}
                toolbar={{
                  options: [
                      'inline',
                      'blockType',
                      'fontSize',
                      'fontFamily',
                      'list',
                      'textAlign',
                      'colorPicker',
                      'link',
                      'embedded',
                      'image',
                      'remove',
                      'history',
                    ],
                   link: { inDropdown: true, linkCallback },
                   embedded: { embedCallback },
                   fontFamily: {
                    options: [
                      '宋體',
                      '黑體',
                      '楷體',
                      '微軟雅黑',
                      'Arial',
                      'Georgia',
                      'Impact',
                      'Tahoma',
                      'Times New Roman',
                      'Verdana',
                    ],
                  },
                  image: {
                    uploadCallback: uploadImageCallBack,

                    uploadEnabled: true,
                    alignmentEnabled: true, // 是否顯示排列按鈕 相當于text-align

                    previewImage: true,
                    inputAccept: 'image/*',
                    alt: { present: false, mandatory: false },
                    defaultSize: {
                      height: 'auto',
                      width: 'auto',
                    },
                  },
                }}
                onEditorStateChange={onEditorStateChange}
              />

樣式問題

.demo-editor {
    height: 275px !important;
    border: 1px solid #f1f1f1 !important;
    padding: 5px !important;
    border-radius: 2px !important;
  }
  .toolbar-class div,
  .demo-wrapper div,
  .demo-editor div {
    box-sizing: content-box;
  }

內(nèi)容變化

 function onEditorStateChange(editorState) {
    console.log(draftToHtml(convertToRaw(editorState.getCurrentContent())));
    console.log(editorState);
    const oldState = editorContent; // 變更前的editorState
    const newState = editorState; // 變更后的editorState

    const oldText = oldState.getCurrentContent().getPlainText();
    const newText = newState.getCurrentContent().getPlainText();

    // if (newText !== oldText) {   // 加判斷后居中 列表 不生效,所以注釋
      setEditorContent(editorState);
   //  }
  }

將內(nèi)容轉(zhuǎn)換為html

draftToHtml(convertToRaw(editorContent.getCurrentContent()))

初始內(nèi)容

// 最開始editorContent = EditorState.createEmpty();
// 會報錯 Unknown DraftEntity key: null
// 就改成了以下寫法,完美解決報錯問題

const templateContent = `<div>
</div>`;
const blocksFromHtml = convertFromHTML(templateContent);
const editorStateContentInitial = ContentState.createFromBlockArray(
  blocksFromHtml.contentBlocks,
  blocksFromHtml.entityMap,
);

  const [editorContent, setEditorContent] = useState(EditorState.createWithContent(editorStateContentInitial));


校驗url合法性

 function checkURL(URL = '') {
    const str = URL;
    const Expression = /http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w- .\/?%&=]*)?/;
    const objExp = new RegExp(Expression);
    if (objExp.test(str) === true) {
      return true;
    } else {
      return false;
    }
  }

  function linkCallback(url = {}) {
    if (checkURL(url.target)) {
      return url;
    } else {
      message.error('請輸入正確的鏈接地址');
      return '';
    }
  }

  function embedCallback(url = '') {
    if (checkURL(url)) {
      return url;
    } else {
      message.error('請輸入正確的網(wǎng)頁地址');
      return '';
    }
  }

本地上傳及轉(zhuǎn)換為base64壓縮

function uploadImageCallBack(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.readAsDataURL(file);
    const img = new Image();
    // let url = ''
    reader.onload = function(e) {
      img.src = this.result;
    };

    img.onload = function() {
      // console.log(img); // 獲取圖片
      // console.log(img.src.length)
      // 縮放圖片需要的canvas(也可以在DOM中直接定義canvas標簽,這樣就能把壓縮完的圖片不轉(zhuǎn)base64也能直接顯示出來)
      const canvas = document.createElement('canvas');
      const context = canvas.getContext('2d');

      // 圖片原始尺寸
      const originWidth = this.width;
      const originHeight = this.height;

      // 最大尺寸限制,可通過設置寬高來實現(xiàn)圖片壓縮程度
      const maxWidth = 400;
      const maxHeight = 500;
      // 目標尺寸
      let targetWidth = originWidth;
      let targetHeight = originHeight;
      // 圖片尺寸超過300x300的限制
      if (originWidth > maxWidth || originHeight > maxHeight) {
        if (originWidth / originHeight > maxWidth / maxHeight) {
          // 更寬,按照寬度限定尺寸
          targetWidth = maxWidth;
          targetHeight = Math.round(maxWidth * (originHeight / originWidth));
        } else {
          targetHeight = maxHeight;
          targetWidth = Math.round(maxHeight * (originWidth / originHeight));
        }
      }
      // canvas對圖片進行縮放
      canvas.width = targetWidth;
      canvas.height = targetHeight;
      // 清除畫布
      context.clearRect(0, 0, targetWidth, targetHeight);
      // 圖片壓縮
      context.drawImage(img, 0, 0, targetWidth, targetHeight);
      /* 第一個參數(shù)是創(chuàng)建的img對象;第二三個參數(shù)是左上角坐標,后面兩個是畫布區(qū)域?qū)捀?*/

      // 壓縮后的圖片轉(zhuǎn)base64 url
      /* canvas.toDataURL(mimeType, qualityArgument),mimeType 默認值是'image/png';
       * qualityArgument表示導出的圖片質(zhì)量,只有導出為jpeg和webp格式的時候此參數(shù)才有效,默認值是0.92 */
      const newUrl = canvas.toDataURL('image/jpeg', 0.92); // base64 格式
      resolve({
        data: {
          link: newUrl,
        },
      });

      // 也可以把壓縮后的圖片轉(zhuǎn)blob格式用于上傳
      // canvas.toBlob((blob)=>{
      //     console.log(blob)
      //     //把blob作為參數(shù)傳給后端
      // }, 'image/jpeg', 0.92)
    };
  });
}

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容