antd
是基于 Ant Design 设计规范实现的 高质量 React 组件库,我们倾向于只提供符合该规范且带有视觉展现的 UI 组件,也尽量不重复造轮子。
如果要在React项目中使用富文本编辑器,官方推荐使用react-quill 与 braft-editor。 详细点击这里
这篇文章主要介绍Braft Editor与Antd的结合使用。
在Ant Design表单中使用
功能要点
- 使用
BraftEditor.createEditorState
创建editorState - 使用
editorState.toHTML()
实时获取html - 使用
editorState.isEmpty()
进行空值校验
注意事项
- 编辑器组件的数据格式为ediorState,为此在调用setFieldsValue时和在提交之前,需要进行相应的转换(toHTML())
- 进行空值校验的话,需要自定义validator,并通过value.isEmpty()来校验,value就是一个editorState
- 编辑器组件的验证时机需要改成onBlur,以避免不期望的验证提示和不必要的性能开销
- 编辑器的value属性必须是一个editorState对象
- 实际使用时请避免在onChange中直接toHTML,配合节流函数或者在合适的时机使用更恰当
编辑器演示
示例源码
import BaseCmp from '@components/BaseCmp.js'
import { connect } from 'react-redux'
import {
RLInput, RLButton, RLForm, RLFormItem
} from '@components/index.js'
import { DatePicker } from 'antd'
import { createRef } from 'react'
import BraftEditor from 'braft-editor'
import actionInfoManage from '@actions/infoManage/actionInfoManage.js'
import { dealTime, dealDateTime } from '@/libs/utils.js'
import moment from 'moment'
import locale from 'antd/es/date-picker/locale/zh_CN'
class CmpInfoEdit extends BaseCmp {
constructor(props) {
super(props)
if (props.infoId) {
this.infoId = props.infoId
}
this.state = {
infoListInfo: {
title: '',
start_time: '',
content: BraftEditor.createEditorState(null)
}
}
this.form = createRef()
}
componentDidMount() {
if (this.infoId) { // 编辑
this.getInfoDetail(this.infoId)
} else {
this.setState({
infoListInfo: {
...this.state.infoListInfo
}
})
}
}
// 资讯详情
getInfoDetail = (id) => {
actionInfoManage.getInfoDetail({id}).then(res => {
if (res.code === 200) {
const data = res.data
let userList = data.invite_uids
this.setState({
userList,
infoListInfo: {
...data,
start_time: moment(dealTime(data.start_time, 'YYYY-MM-DD HH:mm')),
content: BraftEditor.createEditorState(data.content),
}
}, () => {
// 给表单重置值
this.form && this.form.setFieldsValue(this.state.infoListInfo)
})
} else {
this.showToast({ type: 'error', content: res.msg })
}
})
}
editFailed = (res) => {
this.showToast({ content: '您有必填项未填写', type: 'success' })
}
editConfirm = (values) => {
console.log('onFinish', values)
this.setState({
addLoading: true
})
let { start_time } = values
const { title, content } = this.state.infoListInfo
const params = {
title,
start_time: dealDateTime(start_time.format('YYYY-MM-DD HH:mm')),
content: content.toHTML()
}
if (this.infoId) { // 编辑
actionInfoManage.infoEdit({ ...params, id: this.infoId }).then(res => {
if (res.code === 200) {
this.showToast({ content: '编辑成功', type: 'success' })
this.props.changePage('list')
} else {
this.showToast({ type: 'error', content: res.msg })
}
}).finally(() => {
this.setState({
addLoading: false
})
})
} else { // 创建
actionInfoManage.infoAdd(params).then(res => {
if (res.code === 200) {
this.showToast({ type: 'success', content: '创建成功' })
this.props.changePage('list')
} else {
this.showToast({ type: 'error', content: res.msg })
}
}).finally(() => {
this.setState({
addLoading: false
})
})
}
}
disabledDate = (current) => {
return current && current < moment().startOf('day')
}
render() {
return (
<div className='page-info-edit'>
<RLForm
ref={form => this.form = form}
labelCol={{ style: { width: 150, marginRight: 20, textAlign: 'right' } }}
labelAlign='left'
wrapperCol={{ style: { span: 24, marginRight: 30 } }}
onFinish={this.editConfirm}
onFinishFailed={this.editFailed}
initialValues={this.state.infoListInfo}
validateTrigger='onBlur'
>
<RLFormItem
name='title'
label='资讯主题'
colon={false}
rules={[
{
required: true,
message: '请输入资讯主题'
}, {
max: 50,
message: '资讯主题最多50个字符'
}
]}
>
<RLInput
placeholder='请输入资讯主题'
style={{ width: 360 }}
value={this.state.infoListInfo.title}
onChange={e => {
this.setState({
infoListInfo: {
...this.state.infoListInfo,
title: e.target.value
}
})
}}
/>
</RLFormItem>
<RLFormItem
name='start_time'
label='发布时间'
colon={false}
rules={[
{
required: true,
message: '请选择发布时间'
}
]}
>
<DatePicker
allowClear
locale={locale}
showTime
disabledDate={this.disabledDate}
format={'YYYY-MM-DD HH:mm'}
placeholder='请选择日期时间'
/>
</RLFormItem>
<RLFormItem
name='content'
label='正文内容'
colon={false}
rules={[
{
required: true,
validator: (rule, value) => {
if (value.isEmpty()) {
return Promise.reject('请输入正文内容')
} else {
return Promise.resolve()
}
}
}
]}
>
<BraftEditor
value={this.state.infoListInfo.content}
onChange={editorState => {
this.setState({
infoListInfo: {
...this.state.infoListInfo,
content: editorState
}
})
}}
media={{
accepts: {
image: 'image/jpeg,image/png',
video: 'video/mp4',
audio: 'audio/mpeg,audio/mp3',
},
uploadFn: (upload) => {},
// onChange(...rest) {
// console.log('onChange---rest', rest)
// }
}}
style={{ border: '1px solid #d1d1d1', borderRadius: 3, background: '#fff' }}
/>
</RLFormItem>
<RLFormItem>
<div style={{ display: 'flex', justifyContent: 'center' }}>
<RLButton
type="default"
label='取消'
width={80}
style={{ display: 'inline-block' }}
onClick={() => {
this.props.changePage('list')
}}
/>
<RLButton
type="primary"
htmlType="submit"
label={this.infoId ? '保存' : '创建'}
style={{ marginLeft: 40, display: 'inline-block' }}
loading={this.state.addLoading}
width={80}
/>
</div>
</RLFormItem>
</RLForm>
</div>
)
}
}
export default connect((store, props) => {
return {
...props
}
})(CmpInfoEdit)
空值校验
使用isEmpty()
校验,rules中的代码如下:
rules={[
{
required: true,
validator: (rule, value) => {
if (value.isEmpty()) {
return Promise.reject('请输入正文内容')
} else {
return Promise.resolve()
}
}
}
]}
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!