【详解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,不会换行展示。
相关推荐
塞尔维亚大汉13 小时前
鸿蒙内核源码分析(用户态锁篇) | 如何使用快锁Futex(上)
harmonyos·源码阅读
mao毛1 天前
go Mutex 深入理解
go·源码阅读
塞尔维亚大汉1 天前
鸿蒙内核源码分析(消息封装篇) | 剖析LiteIpc 进程通讯内容
harmonyos·源码阅读
Jayconscious1 天前
React源码解析(五):hook原理
前端·react.js·源码阅读
塞尔维亚大汉1 天前
鸿蒙内核源码分析(共享内存) | 进程间最快通讯方式
harmonyos·源码阅读
南风lof3 天前
面试官:看过HashMap的源码吗?说说HashMap的原理
源码阅读
sophie旭5 天前
《深入浅出react开发指南》总结之 10.1 React运行时总览
前端·react.js·源码阅读
塞尔维亚大汉20 天前
鸿蒙内核源码分析(并发并行篇) | 听过无数遍的两个概念
harmonyos·源码阅读
塞尔维亚大汉20 天前
鸿蒙内核源码分析——(自旋锁篇)
harmonyos·源码阅读