ant design Form必填校验失败自动滚动到第一条 scrollToFirstError scrollIntoView

老规矩,话不多说,直接上实现方式
注意:本帅用的版本 “antd”: “4.16.13”,
前提代码如下

 const generateUUID = () => {
    let d = new Date().getTime();
    const uuid = 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, (c: any) => {
      const r = (d + Math.random() * 16) % 16 | 0;
      d = Math.floor(d / 16);
      return (c == 'x' ? r : (r & 0x3) | 0x8).toString(16);
    });
    return uuid;
  };
  const arrs = [];
  for (let i = 20; i--; ) {
    const uuid = generateUUID();
    arrs.push({
      label: uuid,
      name: uuid,
      key: uuid,
    });
  }
  const [state, setstate] = useState([]);
  // setstate(arrs);
  useEffect(() => {
    setTimeout(() => {
      console.log(arrs, 'arrs');
      setstate(arrs);
    }, 200);
  }, []);

方式一:scrollToFirstError

//首先给Form添加一个属性 scrollToFirstError={true}
//然后给button按钮添加属性 htmlType="submit" 即可
//代码如下
<Form form={form} name="basic" scrollToFirstError={true}>
  <Form.Item
    id="sadfasf"
    label="asdfa"
    name="sadfasf"
    rules={[{ required: true, message: "Please input your password!" }]}
  >
    <Input.Password />
  </Form.Item>
  <Form.Item
    id="aaaa"
    label="aaaa"
    name="aaaa"
    rules={[{ required: true, message: "Please input your password!" }]}
  >
    <Input.Password />
  </Form.Item>
  {state.map((item) => {
    return (
      <Form.Item
        key={item.key}
        label={item?.label}
        name={item?.name}
        rules={[{ required: false, message: "Please input your password!" }]}
      >
        <Input.Password />
      </Form.Item>
    );
  })}
  <Button type="primary" htmlType="submit">
    Submit
  </Button>
</Form>;

方式二:onFinishFailed

//失败就会触发该方法
//代码如下:
<Form
  form={form}
  name="basic"
  onFinishFailed={() => {
  	//关键代码
    const errorList = (document as any).querySelectorAll(".ant-form-item-has-error");
    //由于校验失败ant会自动给失败表单项添加类名,直接获取即可
    errorList[0].scrollIntoView({
      block: "center",
      behavior: "smooth",
    });
  }}
  //注意:由于dom更新异步,可能会获取不到,可以在setTimeout()中操作,vue的使用nextTick()即可
>
  <Form.Item
    id="sadfasf"
    label="asdfa"
    name="sadfasf"
    rules={[{ required: true, message: "Please input your password!" }]}
  >
    <Input.Password />
  </Form.Item>
  <Form.Item
    id="aaaa"
    label="aaaa"
    name="aaaa"
    rules={[{ required: true, message: "Please input your password!" }]}
  >
    <Input.Password />
  </Form.Item>
  {state.map((item) => {
    return (
      <Form.Item
        key={item.key}
        label={item?.label}
        name={item?.name}
        rules={[{ required: false, message: "Please input your password!" }]}
      >
        <Input.Password />
      </Form.Item>
    );
  })}
  <Button type="primary" htmlType="submit">
    Submit
  </Button>
</Form>;

方式三:自定义表单项

很多情况下,表单项是通过接口获取渲染的,页面布局可能是自定义的,或嵌套多层div

//类似这种嵌套多层盒子,可能就会失效
           {state.map((item) => {
              return (
                <div>
                  <div>
                    <div>
                      <span></span>
                      <div>
                        <Form.Item
                          key={item.key}
                          label={item?.label}
                          name={item?.name}
                          rules={[{ required: false, message: 'Please input your password!' }]}
                        >
                          <Input.Password />
                        </Form.Item>
                      </div>
                    </div>
                  </div>
                </div>
              );
            })}
//这时候必须要改盒子绑定一定id才会生效
<Form form={form} name="basic" scrollToFirstError={true}>
  <Form.Item
    id="sadfasf"
    label="asdfa"
    name="sadfasf"
    rules={[{ required: true, message: "Please input your password!" }]}
  >
    <Input.Password />
  </Form.Item>
  <Form.Item
    id="aaaa"
    label="aaaa"
    name="aaaa"
    rules={[{ required: true, message: "Please input your password!" }]}
  >
    <Input.Password />
  </Form.Item>
  {state.map((item) => {
    return (
                <div id={item.name}>
                  <div>
                    <div>
                      <span></span>
                      <div>
                        <Form.Item
                          key={item.key}
                          label={item?.label}
                          name={item?.name}
                          rules={[{ required: false, message: 'Please input your password!' }]}
                        >
                          <Input.Password />
                        </Form.Item>
                      </div>
                    </div>
                  </div>
                </div>
    );
  })}
  <Button type="primary" htmlType="submit">
    Submit
  </Button>
</Form>;

在Tabs遇到的问题

可能有个需求,切换对应的tabs,获取相应的表单列表,那么问题就来了,必填项校验失败后,自动滚到到第一个必填项只在第一个tab中生效,其他的不生效。所以我目前是通过销毁隐藏的dom来解决(destroyInactiveTabPane
完整代码如下

    <Tabs destroyInactiveTabPane defaultActiveKey="1" onChange={onChange} tabPosition="left">
      <TabPane tab="Tab 1" key="1">
        <div className={styles.con} id="crfDetailContent">
          <Form
            form={form}
            name="basic"
            labelCol={{ span: 8 }}
            wrapperCol={{ span: 16 }}
            onFinishFailed={() => {
            //注意,用方式一也是可以的---scrollToFirstError
              let str = 'sadfasf';
              const errorDom: any = document.getElementById(str);
              errorDom.scrollIntoView({
                block: 'center',
                behavior: 'smooth',
              });
            }}
          >
            {console.log('state', state)}
            <hr style={{ marginTop: 30 }} />

            <div>
              <div>
                <div id="sadfasf">
                  <Form.Item
                    id="sadfasf"
                    label="asdfa"
                    name="sadfasf"
                    rules={[{ required: true, message: 'Please input your password!' }]}
                  >
                    <Input.Password />
                  </Form.Item>
                </div>
              </div>
            </div>
            <div>
              <Form.Item
                id="aaaa"
                label="aaaa"
                name="aaaa"
                rules={[{ required: true, message: 'Please input your password!' }]}
              >
                <Input.Password />
              </Form.Item>
            </div>
            {state.map((item) => {
              return (
                <div>
                  <div>
                    <div>
                      <span></span>
                      <div>
                        <Form.Item
                          key={item.key}
                          label={item?.label}
                          name={item?.name}
                          rules={[{ required: false, message: 'Please input your password!' }]}
                        >
                          <Input.Password />
                        </Form.Item>
                      </div>
                    </div>
                  </div>
                </div>
              );
            })}
            <Button type="primary" htmlType="submit">
              Submit
            </Button>
          </Form>
        </div>
      </TabPane>
      <TabPane tab="Tab 2" key="2">
        <div className={styles.con} id="crfDetailContent">
          <Form
            form={form}
            name="basic"
            labelCol={{ span: 8 }}
            wrapperCol={{ span: 16 }}
            // onFinish={onFinish}
            onFinishFailed={() => {
              let str = 'sadfasf';
              const errorDom: any = document.getElementById(str);
              errorDom.scrollIntoView({
                block: 'center',
                behavior: 'smooth',
              });
            }}
          >
            <hr style={{ marginTop: 30 }} />

            <div>
              <div>
                <div id="sadfasf">
                  <Form.Item
                    id="sadfasf"
                    label="asdfa"
                    name="sadfasf"
                    rules={[{ required: true, message: 'Please input your password!' }]}
                  >
                    <Input.Password />
                  </Form.Item>
                </div>
              </div>
            </div>
            <div>
              <Form.Item
                id="aaaa"
                label="aaaa"
                name="aaaa"
                rules={[{ required: true, message: 'Please input your password!' }]}
              >
                <Input.Password />
              </Form.Item>
            </div>
            {state.map((item) => {
              return (
                <div>
                  <div>
                    <div>
                      <span></span>
                      <div>
                        <Form.Item
                          key={item.key}
                          label={item?.label}
                          name={item?.name}
                          rules={[{ required: false, message: 'Please input your password!' }]}
                        >
                          <Input.Password />
                        </Form.Item>
                      </div>
                    </div>
                  </div>
                </div>
              );
            })}
            <Button type="primary" htmlType="submit">
              Submit
            </Button>
          </Form>
        </div>
      </TabPane>
      <TabPane tab="Tab 3" key="3">
        Content of Tab Pane 3
      </TabPane>

你可能感兴趣的:(前端,react,前端,reactjs)