React 中使用富文本编辑器 Braft Editor ,并集成上传图片功能
Braft Editor 是基于draft-js开发的富文本编辑器,适用于 React 框架。
1. 安装
使用npm
npm install braft-editor --save
使用yarn
yarn add braft-editor
2. 基本使用
import React, { Component } from 'react'
import BraftEditor from 'braft-editor'
import 'braft-editor/dist/index.css'
export default class Main extends Component {
state = {
editorState: BraftEditor.createEditorState('<p>初始值</p>'), // 设置编辑器初始内容
outputHTML: '<p></p>' // 编辑器输出内容
}
componentDidMount () {
this.setState({
editorState: BraftEditor.createEditorState('<p>hello,<b>world!</b><p>')
})
}
handleChange = (editorState) => {
this.setState({
editorState: editorState,
outputHTML: editorState.toHTML()
}, () => {
console.log(editorState)
console.log(this.state.outputHTML)
})
}
render () {
const { editorState, outputHTML } = this.state
return (
<div>
<div className="editor-wrapper">
<BraftEditor
value={editorState}
onChange={this.handleChange}
/>
</div>
</div>
)
}
}
2. 自定义内置控件
Braft Editor使用 controls 属性指定需要展示的控件;使用contentStyle调整编辑区域的高度。
render () {
const controls = [
'undo', 'redo', 'separator',
'font-size', 'line-height', 'letter-spacing', 'separator',
'text-color', 'bold', 'italic', 'underline', 'strike-through', 'separator',
'superscript', 'subscript', 'remove-styles', 'emoji', 'separator', 'text-indent', 'text-align', 'separator',
'headings', 'list-ul', 'list-ol', 'blockquote', 'code', 'separator',
'link', 'separator', 'hr', 'separator',
'media',
'separator',
'clear'
]
return (
<div className="editor-wrapper">
<BraftEditor
controls={controls}
contentStyle={{height: 210, boxShadow: 'inset 0 1px 3px rgba(0,0,0,.1)'}}
/>
</div>
)
}
3. 集成 Ant Design 上传组件
Braft Editor上传图片会默认转成base64, 下面将使用Ant Design 的上传组件改成上传到服务器的方法:
- 使用ContentUtils来将上传后的图片插入到编辑器,安装:
yarn add braft-utils
- 使用component类型的extendControls将Upload组件集成到编辑器工具栏
import React, { Component } from 'react'
import BraftEditor from 'braft-editor'
import 'braft-editor/dist/index.css'
export default class Main extends Component {
state = {
editorState: BraftEditor.createEditorState(null)
}
componentDidMount () {
this.setState({
editorState: BraftEditor.createEditorState('<p>hello,<b>world!</b><p>')
})
}
onOk = () => {
this.props.form.validateFields((err, fieldsValue) => {
if (!err) {
console.log(fieldsValue)
}
})
}
beforeUpload = file => {
this.props.form.setFieldsValue({
content: ContentUtils.insertMedias(this.props.form.getFieldValue('content'), [{
type: 'IMAGE',
url: imgUrl, // imgUrl 为上传成功后 后台返回的url地址
}])
return false
}
render () {
const {
form: { getFieldDecorator },
} = this.props
const { editorState } = this.state
const formItemLayout = {
labelCol: {
sm: { span: 4 },
},
wrapperCol: {
sm: { span: 20 },
},
}
const controls = [
'undo', 'redo', 'separator',
'font-size', 'line-height', 'letter-spacing', 'separator',
'text-color', 'bold', 'italic', 'underline', 'strike-through', 'separator',
'superscript', 'subscript', 'remove-styles', 'emoji', 'separator', 'text-indent', 'text-align', 'separator',
'headings', 'list-ul', 'list-ol', 'blockquote', 'code', 'separator',
'link', 'separator', 'hr', 'separator',
// 'media',
'separator',
'clear'
]
const extendControls = [
{
key: 'antd-uploader',
type: 'component',
component: (
<Upload
accept="image/*"
showUploadList={false}
beforeUpload={this.beforeUpload}
>
{/* 这里的按钮最好加上type="button",以避免在表单容器中触发表单提交,用Antd的Button组件则无需如此 */}
<button type="button" className="control-item button upload-button" data-title="插入图片">
<Icon type="picture" theme="filled" />
</button>
</Upload>
)
}
]
return (
<div>
<div className="editor-wrapper">
<Form {...formItemLayout}>
<Form.Item label="标题">
{getFieldDecorator(`title`, {
initialValue: '',
rules: [{ required: true, message: '请输入标题' }],
})(
<Input placeholder="请输入" allowClear style={{ width: 300 }} />
)}
</Form.Item>
<Form.Item label="内容">
{getFieldDecorator(`content`, {
validateTrigger: 'onBlur',
initialValue: editorState,
rules: [{ required: true, message: '请输入内容' }],
})(
<BraftEditor
className={styles.editorStyle}
contentStyle={{ height: 160, boxShadow: 'inset 0 1px 3px rgba(0,0,0,.1)' }}
controls={controls}
extendControls={extendControls}
placeholder="请输入正文内容"
/>
)}
</Form.Item>
<Form.Item>
<Button type="primary" onClick={this.onOk}>
确定
</Button>
</Form.Item>
</Form>
</div>
</div>
)
}
}