如何使用antDesign的Form组件实现类似Youtube的评论表单?

需求

想使用antdesign的Form实现类似youtube的评论表单。

  • 初始包括

    • 头像
    • 输入框

commentBox-form-default.png

  • 聚焦(点击输入框或tab)输入框的时候

    • 输入框下面显示取消按钮评论按钮

      • 两者靠右对齐
      • 当输入框中的内容为空的时候,评论按钮disabled

commentBox-form-focus.png

  • 取消输入框聚焦(鼠标点击其他位置或tab到其他可聚焦元素)的时候,保持不变。
  • 按取消键,输入框底部的两个按钮消失,当前输入框中的内容清空。

尝试

codesandbox

import { Form, Avatar, Flex, Input, Button, Space } from "antd";
import React from "react";

function CommentForm() {
  const [show, setShow] = React.useState(false);
  const [form] = Form.useForm();
  const comment = Form.useWatch("comment", form);

  function handleReset() {
    console.log("handle reset");
    form.resetFields();
    setShow(false);
  }
  console.log("comment ", comment);
  return (
    <Flex gap="small" align="start">
      <Avatar>P</Avatar>
      <Form
        onFinish={() => console.log("Finished")}
        className="grow"
        form={form}
      >
        <Form.Item name="comment">
          <Input
            placeholder="添加一条评论"
            onFocus={() => !show && setShow(true)}
          />
        </Form.Item>
        {show && (
          <Flex justify="end">
            <Form.Item wrapperCol={{ span: 4, offset: 0 }}>
              <Space>
                <Button htmlType="reset" onClick={handleReset}>
                  取消
                </Button>
                <Button htmlType="submit" disabled={!comment}>
                  评论
                </Button>
              </Space>
            </Form.Item>
          </Flex>
        )}
      </Form>
    </Flex>
  );
}

export default CommentForm;

问题:

  1. 如何在聚焦时候的时候让两个按钮出现同时在取消聚焦的时候保持不变呢?

    • onFocus + show state
    • 还有其他更好的方案吗?
  2. 如何使两个按钮向右对齐?

    • 方案一: 在Form.Item的外面套一层Flex, 设置justify="end"
    • 方案二: Form其实使用了栅格来对Form.Item来进行布局, 设置wrapperCol={{span: ?, offset: ?}}offset只能相对于左侧,设置多少得用眼来估计,并不准确。
    • 还有其他更好的方案吗?
  3. 如何在点击取消按钮的时候使按钮消失,并清空输入框?

    • onClicksetShow(false)使按钮消失
    • 如何清空输入框?

      • 使用Form.useForm()产生一个formInstance传入Form,然后在onClick中调用resetFields,但是当传入Form的时候报错了Cannot set properties of undefined (setting 'name')

        • 后来发现应该是const [form] = Form.useForm()而不是const form = Form.useForm()
  4. 如何知道当前的输入框是否为空?

    • 方案一:设置一个新的状态,将value, onChange绑定到Input上?读文档发现表单控件会自动生成valueonChange来控制数据,不能再使用value来设置数据,不应该使用setState

      • 行不通
    • 方案二:借助Form.useWatch("comment", form)就可以获取当前comment的值了。

还有其他更优雅的实现方案吗?

附文档中相关说明:

被设置了 name 属性的 Form.Item 包装的控件,表单控件会自动添加 value(或 valuePropName 指定的其他属性) onChange(或 trigger 指定的其他属性),数据同步将被 Form 接管,这会导致以下结果:

  • 你不再需要也不应该用 onChange 来做数据收集同步(你可以使用 Form 的 onValuesChange),但还是可以继续监听 onChange 事件。
  • 你不能用控件的 value 或 defaultValue 等属性来设置表单域的值,默认值可以用 Form 里的 initialValues 来设置。注意 initialValues 不能被 setState 动态更新,你需要用 setFieldsValue 来更新。
  • 你不应该用 setState,可以使用 form.setFieldsValue 来动态改变表单值。
阅读 1k
1 个回答
import React from 'react';
import { Form, Avatar, Flex, Input, Button, Space } from 'antd';

function CommentForm() {
  const [form] = Form.useForm();
  const [show, setShow] = React.useState(false);
  const comment = Form.useWatch("comment", form);

  function handleReset() {
    form.resetFields();
    setShow(false);
  }

  return (
    <Flex gap="small" align="start">
      <Avatar>P</Avatar>
      <Form form={form} onFinish={() => console.log("Finished")} className="grow">
        <Form.Item name="comment">
          <Input
            placeholder="添加一条评论"
            onFocus={() => setShow(true)}
          />
        </Form.Item>
        {show && (
          <Flex justify="end" style={{ width: '100%' }}>
            <Button htmlType="reset" onClick={handle(Reset)}>
              取消
            </Button>
            <Button type="primary" htmlType="submit" disabled={!comment}>
              评论
            </Button>
          </Flex>
        )}
      </Form>
    </Flex>
  );
}

export default CommentForm;
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进