实现方式
            
            
              typescript
              
              
            
          
          <ProTable
  rowKey='id'
  search={{
    span: 5,
    defaultFormItemsNumber: 4,
    submitterColSpanProps: {
      // @ts-ignore
      span: 'auto',
      flex: '20',
    },
/>源码解析
spanSize
spanSize 决定了每行可容纳的表单项个数。
            
            
              typescript
              
              
            
          
          const spanSize = useMemo(
  () => getSpanConfig(layout, width + 16, span),
  [layout, width, span],
);getSpanConfig
getSpanConfig返回一个对象,包含span、layout属性。
- 如果传入的span是一个具体数字,就直接返回这个值,不需要做响应式适配。
- 如果传入的span是一个响应式对象(例如span = { sm: 3, md: 2 }),生成spanConfig。
spanConfig 是一个二维数组, 其中每个元素可以是 string 或 number 类型。每个数组包含三项:
1.1 对应断点的最大宽度(如 xs, sm, md 等对应的宽度)。
1.2 每个表单项的 span 宽度,计算方式是 24 / span[key],这里 24 是栅格系统的总列数。
1.3 布局方式,默认为 'horizontal'。
- 如果未传入span,使用默认断点配置。
找到当前width落在哪个断点区间,加了16是考虑row的-8pxmargin的两侧padding。
- 如果找不到断点(例如宽度特别大或异常),默认使用span = 8和layout = 'horizontal'
- 否则使用找到的断点的配置值
            
            
              typescript
              
              
            
          
          const getSpanConfig = (
  layout: FormProps['layout'],
  width: number,
  span?: SpanConfig,
): { span: number; layout: FormProps['layout'] } => {
  if (span && typeof span === 'number') {
    return {
      span,
      layout,
    };
  }
  const spanConfig: (string | number)[][] = span
    ? ['xs', 'sm', 'md', 'lg', 'xl', 'xxl'].map((key) => [
        CONFIG_SPAN_BREAKPOINTS[key as 'xs'],
        24 / (span as any)[key as 'sm'],
        'horizontal',
      ])
    : BREAKPOINTS[(layout as 'default') || 'default'];
  const breakPoint = (spanConfig || BREAKPOINTS.default).find(
    (item) => width < (item[0] as number) + 16, // 16 = 2 * (ant-row -8px margin)
  );
  if (!breakPoint) {
    return {
      span: 8,
      layout: 'horizontal',
    };
  }
  return {
    span: 24 / (breakPoint[1] as number),
    layout: breakPoint?.[2] as 'horizontal',
  };
};showLength
用于控制默认展示几个表单项,避免换行。
            
            
              typescript
              
              
            
          
          const showLength = useMemo(() => {
  if (defaultFormItemsNumber !== undefined) {
    return defaultFormItemsNumber;
  }
  if (defaultColsNumber !== undefined) {
    // 折叠为一行,需要处理多行的情况请使用 defaultFormItemsNumber
    const oneRowControlsNumber = 24 / spanSize.span - 1;
    return defaultColsNumber > oneRowControlsNumber
      ? oneRowControlsNumber
      : defaultColsNumber;
  }
  return Math.max(1, 24 / spanSize.span - 1);
}, [defaultColsNumber, defaultFormItemsNumber, spanSize.span]);
defaultFormItemsNumber代表默认展示几个表单项,span是配置列数,一般而言是 8 的倍数。
- 当defaultFormItemsNumber存在时,以defaultFormItemsNumber的值为主
- 当defaultColsNumber存在时,会根据spanSize.span获得一行能放几个表单项oneRowControlsNumber,即const oneRowControlsNumber = 24 / spanSize.span - 1;。当defaultColsNumber > oneRowControlsNumber时,则返回oneRowControlsNumber,否则返回defaultColsNumber
- 当defaultFormItemsNumber和defaultColsNumber都不存在时,返回Math.max(1, 24 / spanSize.span - 1)
即 "最多一行展示多少减去一个按钮",但最少保证展示一个。
processedList
processedList 用于遍历所有表单项,并根据 showLength 控制哪些需要折叠隐藏。
totalSize是用于计算当前一行的表单项数,当totalSize > showLength,则把剩下的表单项的hidden属性变为true进行隐藏
            
            
              typescript
              
              
            
          
          const processedList = flatMapItems(items, props.ignoreRules).map(
  (
    item,
    index,
  ): { itemDom: React.ReactNode; hidden: boolean; colSpan: number } => {
    // 如果 formItem 自己配置了 hidden,默认使用它自己的
    const colSize = React.isValidElement < any > (item)
      ? (item?.props?.colSize ?? 1)
      : 1;
    const colSpan = Math.min(spanSize.span * (colSize || 1), 24);
    // 计算总的 totalSpan 长度
    totalSpan += colSpan;
    // 计算总的 colSize 长度
    totalSize += colSize;
    // ........................................
    const hidden: boolean =
      (item as ReactElement<{ hidden: boolean }>)?.props?.hidden ||
      // 如果收起了
      (collapsed &&
        (firstRowFull ||
          // 如果 超过显示长度 且 总长度超过了 24
          totalSize > showLength) &&
        !!index);
    
    // ........................................
    
    return {
      itemDom: item,
      colSpan,
      hidden: false,
    };
  },
);submitterColSpanProps
按钮栏配置,控制查询/重置按钮区域的样式
submitterColSpanProps 是一个可选属性,类型为一个对象。该对象使用 Omit 泛型去除了 ColProps 中的 'span' 属性,并新增了一个 'span' 属性,类型为 number 类型。也就是说,submitterColSpanProps 对象除了 'span' 属性外,还可以包含 ColProps 中的其他所有属性。
spanSize.span也用于查询、重置按钮的span
当赋值给span的值为number类型的时候,他会给出现ant-col-number值 ant-col-offset-(24-number值)的css样式
所以在本示例中给出string类型的字符串'auto',则只会出现ant-col-auto,由于不存在这种css样式,所以会受到flex: '20'的影响
            
            
              typescript
              
              
            
          
          const offset = useMemo(() => {
  const offsetSpan =
    (currentSpan % 24) + (props.submitterColSpanProps?.span ?? spanSize.span);
  if (offsetSpan > 24) {
    return 24 - (props.submitterColSpanProps?.span ?? spanSize.span);
  }
  return 24 - offsetSpan;
}, [
  currentSpan,
  (currentSpan % 24) + (props.submitterColSpanProps?.span ?? spanSize.span),
  props.submitterColSpanProps?.span,
]);代码解析
            
            
              typescript
              
              
            
          
          search={{
  span: 5,
  defaultFormItemsNumber: 4,
  submitterColSpanProps: {
    // @ts-ignore
    span: 'auto',
    flex: '20',
  }
}}由于有span: 5,则spanSize
            
            
              typescript
              
              
            
          
          spanSize:{
  span:5,
  layout:'horizontal'
}- 没有defaultFormItemsNumber: 4只有span: 5,则showLength = 3.8,因为向下取整,才会只展示3个
- 有defaultFormItemsNumbe: 4没有span:5,则showLength = 4。而span=8(默认),那么一行展示3个,但是由于defaultFormItemsNumber = 4,会换行展示1个,相当于两行。
- 有defaultFormItemsNumbe: 4有span:5,则showLength = 4。而span=5,在24/5的情况下,向下取整一行展示4个,由于defaultFormItemsNumber = 4,不会换行展示。