前言
最近项目上需要使用富文本编辑器撰写一个类似新闻发布的表单,同时配合当前最流行的UI库,Antd。
在查询了相关的资料以后,发现,“Braft Editor”是一个不错的推荐。
这篇文章主要介绍Braft Editor与Antd的结合使用。
功能实现
文档中本身就已经有记载,关于集成antd的上传。 braft.margox.cn/demos/antd-…
功能要点
- 使用controls或者excludeControls来隐藏编辑器自带的媒体库控件
- 使用component类型的extendControls将Upload组件集成到编辑器工具栏
- 使用ContentUtils来将上传后的图片插入到编辑器
最主要的关键点是补充:customRequest
里面的方法。
封装组件
import request from '@/utils/request';
import { message, Upload } from 'antd';
import BraftEditor from 'braft-editor';
import 'braft-editor/dist/index.css';
import { ContentUtils } from 'braft-utils';
import React, { forwardRef, useEffect } from 'react';
const MyEditor = React.memo(
forwardRef(({ value = '', onChange = () => {} }, ref) => {
const controls = [
'bold',
'italic',
'underline',
'text-color',
'separator',
'link',
'separator',
];
useEffect(() => {
onChange(value);
}, [value]);
const handleChange = (v) => {
onChange(v);
};
const uploadHandler = (param) => {
if (!param.file) {
return false;
}
const fmData = new FormData();
const config = {
headers: { 'content-type': 'multipart/form-data' },
};
fmData.append('file', param.file);
// 需要修改为自己的Url
return request('/api/file/upload', {
method: 'POST',
processData: false,
data: fmData,
config,
})
.then((res) => {
if (res && res.code === 0) {
message.success('上传成功');
// 此处的url需要重写为能返回显示的图片url
onChange(
ContentUtils.insertMedias(value, [
{
type: 'IMAGE',
url: `previewUrl?fileKey=${res.data.fileKey}`,
},
]),
);
} else {
message.error(res?.message || '上传失败');
}
})
.catch(() => {
// const err = new Error('上传失败');
message.error('上传失败');
});
};
const extendControls = [
{
key: 'antd-uploader',
type: 'component',
component: (
<Upload accept="image/*" showUploadList={false} customRequest={uploadHandler}>
{/* 这里的按钮最好加上type="button",以避免在表单容器中触发表单提交,用Antd的Button组件则无需如此 */}
<button
type="button"
className="control-item button upload-button"
data-title="插入图片"
>
上传图片
</button>
</Upload>
),
},
];
return (
<div ref={ref}>
<div className="editor-wrapper">
<BraftEditor
value={value}
onChange={handleChange}
controls={controls}
extendControls={extendControls}
/>
</div>
</div>
);
}),
);
export default MyEditor;
注意点
- 需要后端返回一个相应的上传完成的图片url,或者相应传到oss上的fileKey,用于预览。
- uploadHandler 主要就是这个方法,手动上传图片
使用
import { useMount } from 'ahooks';
import { Button, Col, Form, Input, Layout, message, Row } from 'antd';
import BraftEditor from 'braft-editor';
import 'braft-editor/dist/index.css';
import 'bytemd/dist/index.min.css';
// import zhHans from 'bytemd/lib/locales/zh_Hans.json';
import 'highlight.js/styles/vs.css';
import React from 'react';
import MyEditor from '../../../components/MyEditor/index';
import styles from './index.less';
const Document = () => {
const [form] = Form.useForm();
useMount(() => {
// 测试回填
form.setFieldsValue({
title: "新闻标题",
content: BraftEditor.createEditorState(`
<p>4234324</p><p></p><p></p><div class="media-wrap image-wrap"><img src="xxx.png"/></div><p></p>`),
});
});
const handleOk = () => {
if (!form.getFieldValue('title')) {
message.error('标题不能为空');
return;
}
form
.validateFields()
.then((r) => {
console.log('content', r.content.toHTML());
})
.catch((e) => console.log(e));
};
return (
<div>
<div className={styles.container}>
<Layout style={{ position: 'relative' }}>
<Layout className="site-layout">
<>
<Form
layout="inline"
form={form}
// onFinish={handleSubmit}
initialValues={{ title: '' }}
>
<Row style={{ width: '100%' }}>
<Col span={18}>
<Form.Item name="title" label="">
<Input placeholder="请输入文章标题" />
</Form.Item>
</Col>
<Col style={{ flex: 1 }}>
<Form.Item className="search_item">
<Button type="primary" onClick={() => handleOk()}>
发布
</Button>
</Form.Item>
</Col>
</Row>
<Form.Item name="content" label="内容" noStyle>
<MyEditor />
</Form.Item>
</Form>
</>
</Layout>
</Layout>
</div>
</div>
);
};
export default Document;
提交时需要将内容修改,将内容的值toHTML()
。