134 lines
3.5 KiB
TypeScript
134 lines
3.5 KiB
TypeScript
import React, { useEffect, useState } from 'react';
|
|
import BraftEditor, { EditorState, ExtendControlType, MediaType } from 'braft-editor';
|
|
import classnames from 'classnames';
|
|
import EditorPreview from './EditorPreview';
|
|
import 'braft-editor/dist/index.css';
|
|
|
|
export interface IEditorProps {
|
|
/**
|
|
* 富文本html代码段
|
|
*/
|
|
value: string;
|
|
/**
|
|
* 请求实例
|
|
*/
|
|
request?: any;
|
|
/**
|
|
* 上传接口
|
|
*/
|
|
action?: string;
|
|
/**
|
|
* 上传中除了 order 外的额外参数
|
|
*/
|
|
data?: {
|
|
[propName: string]: any;
|
|
};
|
|
/**
|
|
* 组件样式类名称前缀
|
|
*/
|
|
prefixCls?: string;
|
|
/**
|
|
* 容器节点样式类名称
|
|
*/
|
|
className?: string;
|
|
/**
|
|
* 容器节点样式
|
|
*/
|
|
style?: React.CSSProperties;
|
|
[propName: string]: any;
|
|
}
|
|
// 上传到服务端的排序号
|
|
let order = 0;
|
|
const Editor: React.FC<IEditorProps> = (props) => {
|
|
const { value, request, action, data, prefixCls, className, style, onChange, ...rest } = props;
|
|
// 富文本数据是否初始化
|
|
const [isInit, setIsInit] = useState(false);
|
|
// 富文本
|
|
const [editorState, setEditorState] = useState<EditorState>(BraftEditor.createEditorState(value));
|
|
// 富文本预览
|
|
const [previewVisible, setPreviewVisible] = useState<boolean>(false);
|
|
// onChange
|
|
const handleEditorChange = (newEditorState: EditorState) => {
|
|
if (isInit || (!isInit && value === '<p></p>')) {
|
|
setIsInit(true);
|
|
setEditorState(newEditorState);
|
|
const changeValue = newEditorState.toHTML() === '<p></p>' ? '' : newEditorState.toHTML();
|
|
onChange(changeValue);
|
|
}
|
|
};
|
|
// 富文本预览
|
|
const extendControls: ExtendControlType[] = [
|
|
{
|
|
key: 'preview-button',
|
|
type: 'button',
|
|
text: '预览',
|
|
onClick: () => setPreviewVisible(true),
|
|
},
|
|
];
|
|
// 自定义媒体
|
|
const media: MediaType = {
|
|
uploadFn: async ({ file, progress, error, success }) => {
|
|
// 自定义上传
|
|
const baseRequestForm = request.requestForm.bind(request);
|
|
order += 1;
|
|
baseRequestForm(
|
|
action,
|
|
{ file, order, ...data },
|
|
{
|
|
onUploadProgress: ({ total, loaded }: { total: number; loaded: number }) => {
|
|
progress((loaded / total) * 100);
|
|
},
|
|
},
|
|
)
|
|
.then((res: any) => {
|
|
const newRes = res.value || res.valueObj || {};
|
|
const { imageUrl = '', attachUrl = '', attachId = '' } = newRes;
|
|
res.url = imageUrl || attachUrl;
|
|
res.uid = attachId;
|
|
res.width = '100%';
|
|
res.height = 'auto';
|
|
success(res);
|
|
})
|
|
.catch(error);
|
|
},
|
|
};
|
|
useEffect(() => {
|
|
if (!isInit && value !== '<p></p>') {
|
|
setEditorState(BraftEditor.createEditorState(value));
|
|
setIsInit(true);
|
|
}
|
|
}, [value]);
|
|
return (
|
|
<div>
|
|
<BraftEditor
|
|
className={classnames(className, `${prefixCls}-wrapper`)}
|
|
style={style}
|
|
contentStyle={{ boxShadow: 'inset 0 1px 3px rgba(0,0,0,.1)' }}
|
|
contentClassName="editor-content"
|
|
extendControls={extendControls}
|
|
// media={media}
|
|
value={editorState}
|
|
onChange={handleEditorChange}
|
|
textBackgroundColor={false}
|
|
stripPastedStyles
|
|
{...rest}
|
|
/>
|
|
<EditorPreview
|
|
width={600}
|
|
value={editorState.toHTML()}
|
|
visible={previewVisible}
|
|
onCancel={() => setPreviewVisible(false)}
|
|
/>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
Editor.defaultProps = {
|
|
value: '<p></p>',
|
|
data: {},
|
|
className: '',
|
|
style: {},
|
|
};
|
|
|
|
export default Editor;
|