WangEditor.jsx 2.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. import React, { useState, useRef, useEffect, useCallback } from 'react';
  2. import E from 'wangeditor';
  3. // import PreviewMenu from './PreviewMenu'
  4. import Preview from './Preview';
  5. import { uploadImage } from '@/utils/uploadFile';
  6. export default (props) => {
  7. const ref = useRef();
  8. const editorRef = useRef();
  9. const [preview, setPreview] = useState(false);
  10. // const [content, setContent] = useState()
  11. const inited = useRef(false);
  12. const handleChange = useCallback(
  13. (html) => {
  14. if ((inited.current || html) && typeof props.onChange === 'function') {
  15. inited.current = true;
  16. props.onChange(html);
  17. }
  18. },
  19. [props],
  20. );
  21. const initEditor = useCallback(() => {
  22. const editor = new E(ref.current);
  23. editorRef.current = editor;
  24. // 取消自动 focus
  25. editor.config.focus = false;
  26. // 触发 change
  27. editor.config.onchange = handleChange;
  28. editor.config.zIndex = 100;
  29. // 自定义图片上传
  30. editor.config.uploadImgMaxLength = 1;
  31. editor.config.customUploadImg = (files, insert) => {
  32. if (!files.length) return;
  33. uploadImage(files[0]).then(insert);
  34. };
  35. // 扩展预览按钮
  36. // editor.menus.extend('previewMenu', PreviewMenu)
  37. // PreviewMenu.preview = (html) => setPreview(true)
  38. // 配置菜单
  39. editor.config.menus = [
  40. 'head', // 标题
  41. 'bold', // 粗体
  42. 'fontSize', // 字号
  43. 'fontName', // 字体
  44. 'italic', // 斜体
  45. 'underline', // 下划线
  46. 'strikeThrough', // 删除线
  47. 'foreColor', // 文字颜色
  48. 'backColor', // 背景颜色
  49. 'list', // 列表
  50. 'justify', // 对齐方式
  51. 'quote', // 引用
  52. 'image', // 插入图片
  53. 'undo', // 撤销
  54. 'redo', // 重复
  55. // 'previewMenu'
  56. ];
  57. // 过滤 word 字符
  58. editor.config.pasteFilterStyle = false;
  59. editor.config.pasteTextHandle = (ctt) => {
  60. const regs = [
  61. /<!--\[if [\s\S]*?endif\]-->/gi,
  62. /<[a-zA-Z0-9]+:[^>]+>[^>]*<\/[a-zA-Z0-9]+:[^>]+>/gi,
  63. /<[a-zA-Z0-9]+:[^>]+\/>/gi,
  64. /<style>[\s\S]*?<\/style>/gi,
  65. new RegExp('\u2029', 'ig'), // 替换word分隔符 序号 8233
  66. ];
  67. return regs.reduce((acc, reg) => {
  68. return acc.replace(reg, '');
  69. }, ctt);
  70. };
  71. editor.create();
  72. editor.$textElem.attr('contenteditable', props.contenteditable !== false);
  73. return () => editor.destroy();
  74. }, [props, handleChange]);
  75. useEffect(() => {
  76. initEditor();
  77. }, [initEditor]);
  78. //
  79. useEffect(() => {
  80. if (props.value && !inited.current && editorRef.current) {
  81. inited.current = true;
  82. editorRef.current.txt.html(props.value);
  83. }
  84. }, [props.value]);
  85. return (
  86. <>
  87. <div ref={ref} style={{ textAlign: 'left' }} />
  88. <Preview
  89. width={426}
  90. style={{ width: '426px', height: '863px', margin: 0, padding: 0 }}
  91. visible={preview}
  92. html={props.value}
  93. onCancel={() => setPreview(false)}
  94. />
  95. </>
  96. );
  97. };