【详解ProTable源码】高级筛选栏如何实现一行五列

实现方式

typescript 复制代码
<ProTable
  rowKey='id'
  search={{
    span: 5,
    defaultFormItemsNumber: 4,
    submitterColSpanProps: {
      // @ts-ignore
      span: 'auto',
      flex: '20',
    },
/>

源码解析

github.com/ant-design/...

spanSize

spanSize 决定了每行可容纳的表单项个数。

typescript 复制代码
const spanSize = useMemo(
  () => getSpanConfig(layout, width + 16, span),
  [layout, width, span],
);

getSpanConfig

getSpanConfig返回一个对象,包含spanlayout属性。

  1. 如果传入的span是一个具体数字,就直接返回这个值,不需要做响应式适配。
  2. 如果传入的span是一个响应式对象(例如span = { sm: 3, md: 2 }),生成spanConfig

spanConfig 是一个二维数组, 其中每个元素可以是 stringnumber 类型。每个数组包含三项:

1.1 对应断点的最大宽度(如 xs, sm, md 等对应的宽度)。

1.2 每个表单项的 span 宽度,计算方式是 24 / span[key],这里 24 是栅格系统的总列数。

1.3 布局方式,默认为 'horizontal'

  1. 如果未传入span,使用默认断点配置。

找到当前width落在哪个断点区间,加了16是考虑row的-8pxmargin的两侧padding。

  • 如果找不到断点(例如宽度特别大或异常),默认使用span = 8layout = '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 的倍数。

  1. defaultFormItemsNumber存在时,以defaultFormItemsNumber的值为主
  2. defaultColsNumber存在时,会根据spanSize.span获得一行能放几个表单项oneRowControlsNumber,即const oneRowControlsNumber = 24 / spanSize.span - 1;。当defaultColsNumber > oneRowControlsNumber时,则返回oneRowControlsNumber,否则返回defaultColsNumber
  3. defaultFormItemsNumberdefaultColsNumber都不存在时,返回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'
}
  1. 没有defaultFormItemsNumber: 4只有span: 5,则showLength = 3.8,因为向下取整,才会只展示3个
  2. defaultFormItemsNumbe: 4没有span:5,则showLength = 4。而span=8(默认),那么一行展示3个,但是由于defaultFormItemsNumber = 4,会换行展示1个,相当于两行。
  3. defaultFormItemsNumbe: 4span:5,则showLength = 4。而span=5,在24/5的情况下,向下取整一行展示4个,由于defaultFormItemsNumber = 4,不会换行展示。
相关推荐
程序猿阿越10 小时前
Kafka源码(六)消费者消费
java·后端·源码阅读
zh_xuan6 天前
Android android.util.LruCache源码阅读
android·源码阅读·lrucache
魏思凡9 天前
爆肝一万多字,我准备了寿司 kotlin 协程原理
kotlin·源码阅读
颜酱13 天前
基于Antd的SchemaForm 的表单复杂配置
前端·javascript·ant design
白鲸开源13 天前
一文掌握 Apache SeaTunnel 构建系统与分发基础架构
大数据·开源·源码阅读
Tans523 天前
Androidx Fragment 源码阅读笔记(下)
android jetpack·源码阅读
Tans51 个月前
Androidx Fragment 源码阅读笔记(上)
android jetpack·源码阅读
Tans51 个月前
Androidx Lifecycle 源码阅读笔记
android·android jetpack·源码阅读
凡小烦1 个月前
LeakCanary源码解析
源码阅读·leakcanary
程序猿阿越1 个月前
Kafka源码(四)发送消息-服务端
java·后端·源码阅读