Antd+braft-editor实现动态增减富文本

本文将介绍在React项目中基于Antd的Form去使用Braft-editor实现富文本的动态新增和删除。

一、需求背景

需求内容是点击配置后进入配置模式(如果已存在文本模块要转换为富文本编辑模式),在页面上可以动态新增删除富文本,然后点击保存按钮统一保存所有文本并展示。

交互流程图如下:

二、最终效果

最终实现的效果图如下:

效果图.gif

三、实现过程

富文本的基本使用

基于Antd的Form表单使用富文本可参考官方Demo

动态新增删除富文本

因为富文本组件是放在Form组件里,因此动态新增删除富文本相当于动态增减表单项(Form.List),实现代码如下:

<Form
  onFinish={handleSubmit}
  layout="horizontal"
  autoComplete="off"
>
  <Form.List name="moduleExtras">
    {(fields, { add, remove }) => (
      <>
        {fields.map(field => {
          return (
            <div key={field.key} className={styles.formItem}>
              <div className={styles.formItemHeader}>
                <Form.Item
                  {...field}
                  label="标题"
                  name={[field.name, 'title']}
                  fieldKey={[field.fieldKey, 'title']}
                >
                  <Input placeholder="请输入标题" allowClear style={{ width: 300 }} />
                </Form.Item>
                <Button onClick={() => remove(field.name)} icon={<DeleteOutlined />} danger>
                  删除
                </Button>
              </div>
              <Form.Item
                {...field}
                name={[field.name, 'content']}
                fieldKey={[field.fieldKey, 'content']}
              >
                <BraftEditor
                  style={{ border: '1px solid #dedede', marginTop: 10 }}
                  controls={controls}
                  placeholder="请输入正文内容"
                />
              </Form.Item>
            </div>
          );
        })}
        <Form.Item>
          <Button
            type="default"
            onClick={() => add()}
            icon={<PlusOutlined />}
          >
            新增模块
          </Button>
        </Form.Item>
      </>
    )}
  </Form.List>
  <Form.Item style={{ marginTop: 10 }}>
    <Button type="primary" htmlType="submit">保存配置</Button>
  </Form.Item>
</Form>
复制代码

左下角的新增模块按钮和右上角的删除按钮分别调用Form.List提供的addremove方法即可实现表单的新增和删除。

展示富文本编辑的内容

当点击保存配置按钮时表单的onFinish会帮我们收集表单的数据并作为方法的第一个参数,打印出来可得到以下结果:

moduleExtrasForm.Listname属性,它保存着表单当前收集的数据,content就是富文本实例,要想得到编辑的内容还需要调用editorState.toHTML()获取html

/** 绑定在Form的onFinish */
const handleSubmit = values => {
  params = values.moduleExtras.map(item => ({
    title: item.title,
    content: item.content.toHTML(),
  }));
  console.log(params) // [{title: "111", content: "<p>222</p>"}]
}
复制代码

渲染文本模块就是根据contenthtml来渲染,我并没有采用官方文档上的方法,方法如下:

// 给用于展示HTML内容的容器加上特定的className
<div className="braft-output-content" dangerouslySetInnerHTML={{__html: outputContent}}></div>
复制代码

dangerouslySetInnerHTML是Reac为浏览器DOM提供innerHTML的替换方案,类似vuev-html

这种方法有一个问题就是当html中存在多个空格时,渲染出来的只有一个空格或者为空。

解决方法是给展示的标签添加white-space: preCSS属性即可。

而我展示html的方法是利用官方提供的readOnly属性将富文本设置成只读模式,并且清空工具栏,也能实现上图效果。

<BraftEditor
  value={BraftEditor.createEditorState(content)}
  readOnly
  controls={[]}
  contentStyle={{ height: 'auto', overflowY: 'hidden', paddingBottom: 0 }}
/>
复制代码

给富文本添加上传图片功能

首先参考官方上传图片Demo的方法给富文本添加上传图片的控件。

/** 自定义上传图片控件 */
const extendControls = field => [
  {
    key: 'antd-uploader',
    type: 'component',
    component: (
      <Upload {...uploadFiles}>
        {/* 这里的按钮最好加上type="button",以避免在表单容器中触发表单提交,用Antd的Button组件则无需如此 */}
        <button
          type="button"
          className="control-item button upload-button"
          data-title="插入图片"
          onClick={() => setUploadField(field)}
        >
          插入图片
        </button>
      </Upload>
    ),
  },
];

// 文件上传
  const uploadFiles = {
    accept: 'image/*', // 只接受图片
    name: 'file',
    action: '/uploadUrl', // 这里是上传图片接口的url
    showUploadList: false,
    onChange: info => {
      if (info.file.status === 'done') { // 图片上传成功返回url
        const { moduleExtras } = form.getFieldsValue(); // 获取表单数据
        if (moduleExtras[uploadField.name]) { // uploadField是点击图片时保存的当前表单项的内容,name为索引
          moduleExtras[uploadField.name] = {
            // 用name去获取对应索引的表单项,新增删除表单项key会自增
            ...moduleExtras[uploadField.name], // 重新设置富文本外其他内容,否则会导致除富文本外其他内容被清空
            content: ContentUtils.insertMedias(moduleExtras[uploadField.name].content, [
              {
                type: 'IMAGE',
                url: info.file.response.data.originUrl // 图片url,
              },
            ]),
          };
          // 修改完表单内容后回填
          form.setFieldsValue({ moduleExtras });
          Message.success('上传成功');
        } else {
          Message.warning('上传失败');
        }
      } else if (info.file.status === 'error') {
        Message.error('上传失败');
      }
    },
  };
复制代码

上传功能跟平常使用antd的Upload组件类似,需要注意的是将图片插入到富文本编辑器中需要调用ContentUtils.insertMedias方法,方法的第一个参数是富文本实例,所以在前面需要通过表单获取上传图片对应的表单项下的富文本实例来将图片插入到对应的富文本下。

添加校验功能

利用isEmpty()方法给富文本添加一个非空校验功能,实现代码如下:

<Form.Item
  {...field}
  name={[field.name, 'content']}
  fieldKey={[field.fieldKey, 'content']}
  rules={[
    {
      required: true,
      validator: (_, value) =>
        value.isEmpty() // 调用isEmpty方法检测是否为空
          ? Promise.reject(new Error('正文不可为空'))
          : Promise.resolve(),
    },
  ]}
>
复制代码

给表单设置初始值

最后就是当页面上已添加了几个文本模块时,点击配置按钮后要将文本模块给转换成富文本编辑的模式。

只要将文本模块的数据遍历生成表单初始值的数据,然后传给表单的initialValues即可,实现代码如下:

/** 初始值 */
const initialValues = initialModule.map((item, index) => ({
  fieldKey: index,
  isListField: true,
  key: index,
  name: index,
  title: item.title,
  content: BraftEditor.createEditorState(item.content),
}));
<Form
  form={form}
  onFinish={handleSubmit}
  layout="horizontal"
  initialValues={{ moduleExtras: initialValues }}
  autoComplete="off"
>
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享