Skip to content

Ant Design Skills&Tips

EricYang edited this page Dec 24, 2021 · 22 revisions

重点记录一些antd组件库使用时遇到的问题以及解决方法

Form组件

使用

Form

  • labelCol: { span: 6, offset: 2 }, 大小;
  • wrapperCol: { span: 16 };
  • preserve: boolean 当字段被删除时保留字段值;
  • initialValues: 设置表单域的值,优先级高于Item,不能被 setState 动态更新,需要用 setFieldsValue 来更新;
  • validateTrigger: 统一设置字段触发验证的时机-['onChange','onFocus','onBlur'];
  • onFieldsChange: 字段更新时触发回调事件function(changedFields, allFields);
  • onFinish: 提交表单且数据验证成功后回调事件;
  • onValuesChange: 字段值更新时触发回调事件;
  • form.validateFields(func):手动校验表单内容;
  • Form.create()(MyFormModal):通过create方法传入form参数,之后在MyFormModal组件里就可以接收form,并使用;
  • import { WrappedFormUtils } from 'antd/lib/form/Form.d';// interface Props {form: WrappedFormUtils;}

Form.Item

  • 一种用法:3.x版本
      const { getFieldDecorator } = form;
      // 
      <Form.Item label="我的理由" className="reason" colon={false}>
        {getFieldDecorator('**reason**', {
          rules: [
            { required: true, message: '理由不能为空' }
            { max: 500, message: '不超过500个字' },
          ],
          initialValue: '',
        })(
          <TextAreaWithNum
            placeholder="不超过500个字"
            style={{ height: 200, width: 500 }}
            max={500}
          />
        )}
      </Form.Item>
  • initialValue: 设置子元素默认值,如果与 Form 的 initialValues 冲突则以 Form 为准;
  • normalize: 组件获取值后进行转换,再放入 Form 中。不支持异步,(value, prevValue, prevValues) => any;
  • tooltip: 配置提示信息;
  • colon: 配合 label 属性使用,表示是否显示 label 后面的冒号;
  • rules: 校验规则;
{ required: true, message: 'Please input your password!', max:20, validator: customFunc(rule: Rule, value: string, cb: Promise) }

Form.List

  • 为字段提供数组化管理;
<Form.List>
  {fields =>
    fields.map(field => (
      <Form.Item {...field}>
        <Input />
      </Form.Item>
    ))
  }
</Form.List>

校验

  • const [form] = Form.useForm();此时会报错:Warning: Instance created by useForm is not connected to any Form element. Forget to pass form prop?官方没给出合理的处理方式;

  • 有form属性,设为上面的{form}, 可以通过form.validateFields().then()去校验整个Form表单的字段;
  • scrollToFirstError:长表单校验自动滚动;

  • form.getFieldsValue();获取表单各项的值;

  • form.setFieldsValue();设置表单区域的值;

  • form.resetFields();重置表单的值;// tips:在onOK方法中使用resetFields不当会导致视觉交互问题。

  • onValuesChange:表单数据变化监听事件;

  • <Form.Item> 设置rule进行单项校验:required、max、validateTrigger:['onChange', 'onBlur','onFocus']、validator:customFunc自定义校验方法;

  • 对于customFunc自定义校验方法:能接收到rule、value、callback,通过判断value,然后返回Promise.resolve()/Promise.reject('提示内容');

  • 修改Form.Item中的Input的hover样式,重点在validate失败时border的颜色要变红

// 全局 important
    .ant-form-item-has-error .ant-input,
    .ant-form-item-has-error .ant-input-affix-wrapper {
      &:hover {
        border-color: red !important;
      }
    }
// 在 Input
    .ant-input-affix-wrapper {
      &:hover,
      &:focus {
        border-color: purple;
      }
    }

Modal组件

使用

  • getContainer={Boolean | HTMLElement}:默认挂载到document.body;
  • forceRender:强制刷新;
  • destroyOnClose:关闭的时候销毁组件;
  • maskClosable={false}:点击蒙层是否关闭;
  • afterClose={() => form.resetFields():配合<Form 在一定程度上解决Modal关闭后清空Form内容
  • Antd 4.x 和 Form 一起配合使用时,设置 destroyOnClose 为 true,并且还需要设置 ,还需要手动设置 form.resetFields() 来重置Form 表单的值。
  • Antd 3.x 函数组件需要配合forwardRef
  • 使用Modal.warn()等方法直接弹窗提示时,可以通过className属性添加自定义css样式,配合styled-components的 createGlobalStyle 创建全局样式文件,可以覆盖html的全局样式,然后在index.tsx中引入,作为component使用即可,和AppRouter放在一层。

AutoComplete、Select组件

使用

  • getPopupContainer={(triggerNode) => triggerNode.parentNode}:挂载到DOM,防止options列表滑动;
  • dropdownRender:渲染自定义ReactNode;
  • onSelect={this.onSelect}
  • onSearch={this.onSearch}
  • dataSource:数据;
  • 阻止冒泡:Option的点击事件e中会抛出,e.stopPropagation();e.preventDefault();return false;三连看情况;

Upload

使用方式

  • API有点怪异,使用action的话需要把URL直接写在代码里,而实际应用场景中service都会统一封装,所以不建议使用官方的示例那种用法

  • 自定义用法:使用参考这里;

         showUploadList={{
            showPreviewIcon: true,
            showDownloadIcon: true,
            downloadIcon: 'download',
            showRemoveIcon: true,
            removeIcon: 'delete',
         }}
  • customRequest={this.upload}:自定义上传方法;upload(option):option包含文件信息:option.file.type、option.file.name...可以进行文件校验;
  • 如何显示下载链接?请使用 fileList 属性设置数组项的 url 属性进行展示控制。如果不给fileList传入url属性,则上传后的fileList列表点击时不会下载文件。

Table

使用

  • scroll={{x: 1200,y: 500, scrollToFirstRowOnChange: true,}}:设置表格滚动;
  • pagination:分页:
  • expandable={{ defaultExpandedRowKeys: ['row1', 'row3'] }}:某行是否默认展开;
  • dataSource:数据;
  • columns:列头;
{
  size: 'small',
  total: data.total,
  showQuickJumper: true,
  defaultCurrent: 1,
  current: state.pageNow,
  pageSize: 50,
  showTotal: total => '每页50条 共${total}条',
  onChange: page => onPageSizeChange(page),
}
  • locale:{{emptyText: }}:自定义空内容;
  • loading={{spinning: loading, tip: "加载中...",}}:加载loading;
  • columns:表格列配置:
{
      title: 'columnName',
      dataIndex: 'columnData',
      key: 'column',
      align: 'right',
      width: 120,
      render: text => handleVal(text),// 处理文本
      sorter: (a, b) => a.columnData - b.columnData,// 排序
}

采坑注意

  • 在90.x版本Chrome上,固定列滚动时会有bug,导致某列显示不完全。原因是固定列下方的那几个对应的列(占位列)宽度没有设置成功。
  • 解决方法:根据固定列的实现原理,给占位列设置最小宽度可以解决。
  .ant-table-thead > tr > th {
    white-space: nowrap; // 防止IE等浏览器不支持'max-content'属性 导致内容换行
    border-right: 1px solid #e1e9fe !important;
  }
  .ant-table-thead > tr > th:not:first-child {
    min-width: 100px;
  }

Menu组件

使用

<Menu
  onSelect={handleMenuClick} // 选中事件
  onClick={..} // 点击事件
  onOpenChange={onOpenChange} // submenu展开事件
  style={{ width: 255 }} // 宽
  // defaultOpenKeys={['sub1']} // 默认展开的submenu
  openKeys={selectedSubMenu} // 当前选中的submenu
  // defaultSelectedKeys={['key1']} // 默认选中的menuItem
  mode="inline" // 展示形态
  >
    {renderSubMenu(menuList)} // 自定义方法去渲染
</Menu>

Input组件

使用

  • autoComplete: "off", 可以禁止掉原生input的默认提示行为;

Select组件

  • 自定义option
  • 支持本地过滤、排序
          <Select
            defaultValue={xxx}
            style={xxx}
            onChange={handleChange}
            value={xxx}
            getPopupContainer={(e) => e.parentElement}
            showSearch
            optionFilterProp="children"
            filterOption={(input, option) => option?.props?.children?.toLowerCase().indexOf(input.toLowerCase()) >= 0}
            filterSort={(optionA, optionB) => optionA?.props?.children?.toLowerCase().localeCompare(optionB?.props?.children?.toLowerCase())}
          >
            <Option key="all" value={xxx}>
              全部
            </Option>
            {xxxx &&
              _.map(xxxx, (department) => (
                <Option key={xx.id} value={xx.val}>
                  {xx.name}
                </Option>
              ))}
            <Option key="unset" value={xxx}>
              啦啦啦
            </Option>
          </Select>

Pagination组件

用法

  • 一般会配合table来用,也不排除跟在list后面的情况
  • 样式修改比较费劲,如下实现完全的样式自定义配置:
  .ant-pagination {
    font-size: 14px;
    text-align: center;
    position: relative;
    color: ${theme.font333};
    .ant-pagination-total-text {
      position: absolute;
      left: 0;
    }
    .ant-pagination-prev .ant-pagination-item-link, .ant-pagination-next .ant-pagination-item-link {
      border-radius: 6px;
    }
    .ant-pagination-prev, .ant-pagination-next, .ant-pagination-jump-prev, .ant-pagination-jump-next {
      display: inline-block;
      color: #666;
      text-align: center;
      vertical-align: middle;
      list-style: none;
      border-radius: 6px;
      cursor: pointer;
      transition: all 0.3s;
    }
    .ant-pagination-item {
      border-radius: 6px;
      display: inline-block;
      margin-right: 8px;
      text-align: center;
      vertical-align: middle;
      list-style: none;
      background-color: ${theme.colorWhite};
      border: 1px solid ${theme.colorD9};
      border-radius: 6px;
      outline: 0;
      cursor: pointer;
      user-select: none;
      &.ant-pagination-item-active {
        a {
          color: ${theme.colorWhite};
        }
        background-color: ${theme.color406};
      }
      &:hover:not(.ant-pagination-item-active) {
        border-color: ${theme.color406};
        a {
          color: ${theme.color406};
        }
      }
    }
    .ant-pagination-options-size-changer {
      .ant-select-selector {
        height: 32px;
        line-height: 32px;
        .ant-select-selection-item {
          line-height: 30px;
        }
      }
    }
    .ant-pagination-options-quick-jumper {
      input {
        &:hover,
        &:focus {
          border-color: ${theme.color406};
        }
      }
    }
    .ant-pagination-prev:not(.ant-pagination-disabled) .ant-pagination-item-link,
    .ant-pagination-next:not(.ant-pagination-disabled) .ant-pagination-item-link {
      &:hover {
        border-color: ${theme.color406};
        color: ${theme.color406};
      }
    }
    .ant-pagination-jump-prev .ant-pagination-item-container .ant-pagination-item-link-icon,
    .ant-pagination-jump-next .ant-pagination-item-container .ant-pagination-item-link-icon {
      color: ${theme.color406};
    }
  }

Clone this wiki locally