原生HTML文档案例 wangEditor-master/packages/editor/demo/like-qq-docs.html
WangEdtior
import { useState, useEffect, useMemo } from 'react';
import {
string,
number,
object,
array,
func,
oneOf,
oneOfType
} from "prop-types";
import { merge, noop, isEqual } from "lodash-es";
import cls from 'classnames';
import { Editor, Toolbar } from '@wangeditor/editor-for-react';
import {
IDomEditor,
IEditorConfig,
IToolbarConfig
} from '@wangeditor/editor';
import Content from './Content';
const ENUM_MODE = ["simple", "default"];
WangEditor.propTypes = {
value: oneOfType([array, string]),
onChange: func,
title: string,
titleChange: func,
height: number,
placeholder: string,
mode: oneOf(ENUM_MODE),
className: oneOfType([string, object]),
style: object,
};
WangEditor.defaultProps = {
onChange: noop,
titleChange: noop,
height: 200,
placeholder: "请输入内容...",
mode: "simple"
};
function WangEditor(props) {
const {
value,
onChange,
title,
titleChange,
height,
placeholder,
mode,
className,
style
} = props;
// editor 编辑器实例
const [editorInst, setEditorInst] = useState<IDomEditor | null>(null);
// 编辑器内容
const [content, setContent] = useState(value);
// useEffect 是在render结束之后才执行的
useEffect(() => {
// 及时销毁 editorInst 重要!
return () => {
if (!editorInst) return;
editorInst.destroy();
setEditorInst(null);
};
}, [editorInst]);
// value 改变,设置 content
useEffect(() => {
// 设置内容
if (isEqual(value, content)) return;
setContent(value);
}, [value]);
// 工具栏配置
const toolbarConfig: Partial<IToolbarConfig> = useMemo(() => ({}), []);
// 编辑器配置
const editorConfig: Partial<IEditorConfig> = useMemo(() => ({
placeholder,
// scroll: false, // 禁止编辑器滚动
// maxLength: 1000,
// onMaxLength(editor) {
// console.log('Trigger maxlength callback')
// },
MENU_CONF: {
// onChange(editor: any) {
// console.log(editor.getHtml());
// },
uploadImage: {
// form-data fieldName ,默认值 'wangeditor-uploaded-image'
fieldName: 'your-custom-name',
// 单个文件的最大体积限制,默认为 2M
maxFileSize: 2 * 1024 * 1024, // 1M
// 最多可上传几个文件,默认为 100
maxNumberOfFiles: 10,
// 选择文件时的类型限制,默认为 ['image/*'] 。如不想限制,则设置为 []
allowedFileTypes: ['image/*'],
/**
* 小于该值就插入 base64 格式(而不上传),默认为 0
* 1MB 兆 = 1024KB 千字节 * 1024B 比特 = 1048576 kb 字节
* 1MB = 1024KB
* 1KB = 1024B
* 10 * 1024 * 1024, // 10M 以下插入 base64
*/
// 10 * 1024 * 1024 // 10M 以下
base64LimitSize: 5 * 1024, // 5kb
// 跨域是否传递 cookie ,默认为 false
withCredentials: true,
// 超时时间,默认为 10 秒
timeout: 5 * 1000, // 5 秒
// 自定义增加 http header
headers: {
Accept: 'text/x-json',
otherKey: 'xxx',
},
// 自定义上传参数,例如传递验证的 token 等。参数会被添加到 formData 中,一起上传到服务端。
meta: {
token: 'xxx',
otherKey: 'yyy',
},
},
// fontSize: { // 覆盖默认的配置
// fontSizeList: [
// { name: '26px', value: '26px' },
// ],
// }
}
}), [placeholder]);
// 编辑器内容改变
function handleChange(editor: IDomEditor) {
// const html = editor.getHtml(); // 获取 HTML
// const text = editor.getText(); // 获取纯文本,默认带换行符
// const text = editor.getText().replace(/\n|\r/mg, '');
const json = editor.children; // 获取 JSON []
// editor.getSelectionText() // 选中的文字
setContent(json);
onChange(json, editor);
}
const EditorStyle = useMemo(() => {
return merge({ height, overflow: "hidden auto" }, style);
}, [style, height]);
const isSimple = isEqual(mode, ENUM_MODE[0]);
return (
<div className={cls('z-100', {
__simple__: isSimple,
}, className)}>
{/*工具栏组件*/}
<Toolbar
editor={editorInst}
defaultConfig={toolbarConfig}
mode={mode}
/>
<Content
value={title}
onChange={titleChange}
isSimple={isSimple}
>
{/*编辑器组件*/}
<Editor
defaultConfig={editorConfig}
content={content}
onCreated={setEditorInst}
// 编辑器内容改变
onChange={handleChange}
style={EditorStyle}
mode={mode}
/>
</Content>
</div>
);
}
export default WangEditor;
Content.tsx
/**
* @author lulongwen
* Date: 2023-08-20 21:50
* Description:
*/
import { memo, useState, useEffect } from 'react';
import { string, func, node, bool } from 'prop-types';
import cls from 'classnames';
import styles from "./style.module.less";
Content.propTypes = {
value: string,
onChange: func.isRequired,
children: node,
isSimple: bool,
};
function Content(props) {
const {
value,
onChange,
children,
isSimple,
} = props;
// 标题
const [title, setTitle] = useState(value);
useEffect(() => {
// 设置标题
if (value === title) return;
setTitle(value);
}, [value]);
// 标题组件表单改变
function inputChange(e) {
const inputValue = e.target.value;
setTitle(inputValue);
onChange(inputValue);
}
if (isSimple) {
return children;
}
return (
<div className={styles.editor}>
<section className={styles.area}>
<header className={cls('py-3', styles.border)}>
<input
value={title}
type="text"
placeholder='请输入标题'
className='w-full border-none text-3xl outline-none'
onChange={inputChange}
/>
</header>
{children}
</section>
</div>
);
}
export default memo(Content);
style.module.less
/**
* @author lulongwen
* Date: 2023-02-04 22:53
* Update: 2023-08-20 20:30:41
* Description:
*/
.editor {
position: relative;
height: calc(100% - 50px);
background-color: rgb(245, 245, 245);
overflow-y: auto;
}
.area {
width: 70%;
min-height: 900px;
margin: 24px auto 120px;
padding: 16px 24px 24px;
border: 1px solid #e8e8e8;
background-color: #fff;
box-shadow: 0 2px 10px rgb(0 0 0 / 8%);
.border {
border-bottom: 1px solid #e8e8e8;
}
}