function useColumns<T>(props: TableProps<T>): [InternalColumnProps[][], InternalColumnProps[]] {
const {
components, // 覆盖原生表格标签
rowSelection, // 设置表格行是否可选,选中事件等
expandedRowRender, // 点击展开额外的行,渲染函数。返回值为 null 时,不会渲染展开按钮
expandProps = {}, // 展开参数
columns = [], // 外界传入的columns
childrenColumnName, // 默认是children
} = props;
![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/59dbcdab3b154494b751f61eeebe2432~tplv-k3u1fbpfcp-watermark.image?)
// 下面有getFlattenColumns方法
// getFlattenColumns平铺columns,因为可能有多级表头,所以需要平铺
// getFlattenColumns,注意这个平铺只会搜集叶子节点!!!!
const rows: InternalColumnProps[] = useMemo(
() => getFlattenColumns(columns, childrenColumnName),
[columns, childrenColumnName]
);
// 是否是checkbox
const isCheckbox =
(rowSelection && rowSelection.type === 'checkbox') ||
(rowSelection && !('type' in rowSelection));
// 是否是radio
const isRadio = rowSelection && rowSelection.type === 'radio';
// 展开按钮列的宽度
const { width: expandColWidth } = expandProps;
// 是否有expand—row
const shouldRenderExpandCol = !!expandedRowRender;
const shouldRenderSelectionCol = isCheckbox || isRadio;
// 获取到自定义的操作栏,默认是selectNode和expandNode
const { getHeaderComponentOperations, getBodyComponentOperations } = useComponent(components);
const headerOperations = useMemo(
() =>
getHeaderComponentOperations({
selectionNode: shouldRenderSelectionCol ? 'holder_node' : '',
expandNode: shouldRenderExpandCol ? 'holder_node' : '',
}),
[shouldRenderSelectionCol, shouldRenderExpandCol, getHeaderComponentOperations]
);
const bodyOperations = useMemo(
() =>
getBodyComponentOperations({
selectionNode: shouldRenderSelectionCol ? 'holder_node' : '',
expandNode: shouldRenderExpandCol ? 'holder_node' : '',
}),
[shouldRenderSelectionCol, shouldRenderExpandCol, getBodyComponentOperations]
);
// rowSelection.fixed 表示checkbox是否固定在左边
const selectionFixedLeft = rowSelection && rowSelection.fixed;
// 选择列的宽度
const selectionColumnWidth = rowSelection && rowSelection.columnWidth;
const getInternalColumns = useCallback(
(rows, operations, index?: number) => {
const operationFixedProps: { fixed?: 'left' | 'right' } = {};
const _rows: InternalColumnProps[] = [];
rows.forEach((r, i) => {
const _r = { ...r };
if (!('key' in r)) {
_r.key = _r.dataIndex || i;
}
if (i === 0) {
_r.$$isFirstColumn = true;
if (_r.fixed === 'left') {
operationFixedProps.fixed = _r.fixed;
}
} else {
_r.$$isFirstColumn = false;
}
_rows.push(_r);
});
const expandColumn = shouldRenderExpandCol && {
key: INTERNAL_EXPAND_KEY,
title: INTERNAL_EXPAND_KEY,
width: expandColWidth,
$$isOperation: true,
};
const selectionColumn = shouldRenderSelectionCol && {
key: INTERNAL_SELECTION_KEY,
title: INTERNAL_SELECTION_KEY,
width: selectionColumnWidth,
$$isOperation: true,
};
if (selectionFixedLeft) {
operationFixedProps.fixed = 'left';
}
if (typeof index !== 'number' || index === 0) {
[...operations].reverse().forEach((operation) => {
if (operation.node) {
if (operation.name === 'expandNode') {
_rows.unshift({ ...expandColumn, ...operationFixedProps });
} else if (operation.name === 'selectionNode') {
_rows.unshift({ ...selectionColumn, ...operationFixedProps });
} else {
_rows.unshift({
...operation,
...operationFixedProps,
title: operation.name,
key: operation.name,
$$isOperation: true,
width: operation.width || 40,
});
}
}
});
}
return _rows;
},
[
expandColWidth,
shouldRenderExpandCol,
shouldRenderSelectionCol,
selectionColumnWidth,
selectionFixedLeft,
]
);
const flattenColumns = useMemo(
() => getInternalColumns(rows, bodyOperations),
[rows, getInternalColumns, bodyOperations]
);
// 把表头分组的 columns 分成 n 行,并且加上 colSpan 和 rowSpan,没有表头分组的话是 1 行。
// 获取column的深度
const rowCount = useMemo(
() => getAllHeaderRowsCount(columns, childrenColumnName),
[columns, childrenColumnName]
);
// 分行之后的rows
const groupColumns = useMemo(() => {
if (rowCount === 1) {
return [getInternalColumns(columns, headerOperations, 0)];
}
const rows: InternalColumnProps[][] = [];
const travel = (columns, current = 0) => {
rows[current] = rows[current] || [];
columns.forEach((col) => {
const column: InternalColumnProps = { ...col };
if (column[childrenColumnName]) {
// 求出叶子结点的个数就是colSpan
column.colSpan = getFlattenColumns(col[childrenColumnName], childrenColumnName).length;
column.rowSpan = 1;
rows[current].push(column);
travel(column[childrenColumnName], current + 1);
} else {
column.colSpan = 1;
// 这是
column.rowSpan = rowCount - current;
rows[current].push(column);
}
});
rows[current] = getInternalColumns(rows[current], headerOperations, current);
};
travel(columns);
return rows;
}, [columns, childrenColumnName, rowCount, getInternalColumns, headerOperations]);
return [groupColumns, flattenColumns];
}
export default useColumns;
function getFlattenColumns(columns: InternalColumnProps[], childrenColumnName: string) {
const rows: InternalColumnProps[] = [];
function travel(columns) {
if (columns && columns.length > 0) {
columns.forEach((column) => {
if (!column[childrenColumnName]) {
rows.push({ ...column, key: column.key || column.dataIndex });
} else {
travel(column[childrenColumnName]);
}
});
}
}
travel(columns);
return rows;
}