【详解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,不会换行展示。
相关推荐
王林不想说话15 天前
React + Ant Design 后台项目:63 个业务组件的分层实践
react.js·typescript·ant design
Ai拆代码的曹操21 天前
版本号差一位 Dubbo 灰度就失败:源码级排查
dubbo·源码阅读
5pat54OfCg24 天前
OpenCode 源码拆解(六):系统怎么不崩?——韧性的 3 个设计模式
agent·源码阅读
Ai拆代码的曹操1 个月前
Dubbo 线程池爆满排坑:Linux 用户线程数限制,一个容易被忽略的根因
后端·源码阅读
我是大卫1 个月前
【图】解析《苏格拉底的申辩》,我去死,你们去活
源码阅读
我是大卫1 个月前
解析刘震云的《一句顶一万句》,体会人生苍凉
源码阅读
沙盘客1 个月前
AFSIM 的时间到底是怎么"走"的?——从 2.9.0 源码拆解离散事件时钟
源码阅读
夕夕木各1 个月前
Ant Design 本地构建一直卡在 Bundling?一次 UtooPack 排查记录
前端·ant design
李剑一1 个月前
ant-design-vue 1.x 版本换肤功能开发
前端·vue.js·ant design
jump_jump1 个月前
Kysely 源码解剖:类型安全 SQL 如何走到 AST
node.js·orm·源码阅读