【React + Ant Design】表单如何在前置项未填写时禁止后置项交互并提示

在 react + antd 中,对表单做在前置项未填写时禁用后置项交互并提示的效果。

情景

最近有这么个需求,某个业务中,要填写一张表单,其中有这样两项:选择数据连接和选择数据表,数据表是数据连接下所拥有的表。通常,没选数据连接,数据表就拿不到数据,点击下拉无非是个空的框,这并不影响正常使用,大家都能接收,一般也不会做更精细的要求。但我们的产品要求实现以下效果:未选择数据连接时,无法点击数据表,同时在数据连接下面提示,请选择数据连接。

大致意思就是,没选数据连接的时候,不让下拉数据表选项,点击了就提示你数据连接还没选呢!

思路

项目用的 UI 库是 ant design pro,表单用到了 ProForm, FormItem 以及 Select 等众多输入组件。

笔者最初想着 antd 的表单项能不能为警告消息绑定自定义的变量,这样点击选择数据表的时候判断一下,给数据连接那边挂上消息提示不就好了。很可惜,阅读表单以及表单项的 Api 文档后,发现没有提供绑定自定义消息变量的接口。

没事,继续读 Api 文档,总有别的出路。果然,其中表单 FromInstance 的一项引起了我的注意:validateFields(nameList?: NamePath[]),正常情况下,表单的校验是在 onChange 或者 onSubmit 时自动触发的,validateFields则使得我们能手动触发对指定表单项的检验,那可不就来了嘛,点击选择数据表时,校验一下数据连接有了没,没有的话把数据表选项的点击给阻止掉即可。

方案

  1. 绑定到表单的 ref 实例
  2. 在 数据连接的 组件上添加规则,检验 required
  3. 在 Select 组件外包裹一层 div,在这上面将进行 Select 点击事件的冒泡组织
  4. Select 外层 div 上传入 onPointerDown 事件(为什么不是 onClick 和 onMouseDown,因为通过尝试发现 Select 的点击事件作用在 onPointerDown 上),在点击时,触发对数据连接项的检验,如果检验不通过就阻止 Select 的冒泡点击

伪代码

ts 复制代码
const formRef = useRef<ProFormInstance>();

<ProForm
  layout="horizontal"
  validateTrigger={['onSubmit']}
  formRef={formRef}
>
  <FormItem required name="conn" label="数据连接" rules={[
    { required: true, message: '请选择数据连接' }
  ]}>
    <Select options={conns} />
  </FormItem>
  <FormItem required name="table" label="数据表" rules={[
    { required: true, message: '请选择数据表' }
  }]>
    <div onPointerDown={(e) => {
      formRef.current.validateFields(['conn'])
        .catch(err => {
          console.error(err);
          e.preventDefault();
        })
      }}
    >
      <Select options={tables} />
    </div>
  </FormItem>
</ProForm>

至此,基本达成需求的效果,Bingo!

相关推荐
前端老宋Running13 分钟前
React 的“时光胶囊”:useRef 才是那个打破“闭包陷阱”的救世主
前端·react.js·设计模式
yinuo16 分钟前
前端跨页面通讯终极指南③:LocalStorage 用法全解析
前端
隔壁的大叔24 分钟前
正则解决Markdown流式输出不完整图片、表格、数学公式
前端·javascript
胡楚昊28 分钟前
CTF SHOW逆向
java·服务器·前端
San3035 分钟前
深入 JavaScript 原型与面向对象:从对象字面量到类语法糖
javascript·面试·ecmascript 6
拉不动的猪43 分钟前
前端JS脚本放在head与body是如何影响加载的以及优化策略
前端·javascript·面试
shykevin44 分钟前
Actix-Web完整项目实战:博客 API
前端·数据库·oracle
lichong9511 小时前
RelativeLayout 根布局里有一个子布局预期一直展示,但子布局RelativeLayout被 覆盖了
android·java·前端
Tzarevich1 小时前
从字面量到原型链:JavaScript 面向对象的完整进化史
javascript·设计模式
LengineerC1 小时前
我写了一个VSCode的仿Neovide光标动画
前端·visual studio code