基于vue3.0和element-plus的组件库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

109 lines
3.4 KiB

/**
* usePretextRowHeights
*
* Pre-computes row heights using pretext text measurement.
* For each row, measures each cell's height at the given column width,
* then takes the maximum + padding as the row height.
*/
import { computed, type Ref } from "vue";
import { measureTextHeight } from "./measureText";
import type { ListTableColumn } from "./types";
const DEFAULT_FONT = "14px Inter, sans-serif";
const DEFAULT_LINE_HEIGHT = 20;
const DEFAULT_ROW_PADDING = 5;
const CELL_VERTICAL_PADDING = 12; // top + bottom per cell
export interface RowHeightEntry {
height: number;
isCustomRenderer: boolean;
cellHeights?: RowHeightEntry[];
}
export function usePretextRowHeights<T>(
data: Ref<T[]>,
columns: Ref<ListTableColumn<T>[]>,
columnWidths: Ref<number[]>,
formatCellValue: (row: T, col: ListTableColumn<T>) => string,
options?: {
font?: string;
lineHeight?: number;
rowPadding?: number;
debug?: boolean;
}
) {
const font = options?.font ?? DEFAULT_FONT;
const lineHeight = options?.lineHeight ?? DEFAULT_LINE_HEIGHT;
const rowPadding = options?.rowPadding ?? DEFAULT_ROW_PADDING;
const rowHeights = computed<RowHeightEntry[]>(() => {
if (!data.value.length || !columns.value.length || !columnWidths.value.length) {
return [];
}
return data.value.map((row) => {
let maxCellHeight = lineHeight; // minimum 1 line
let cellHeights: RowHeightEntry[] | undefined = options?.debug ? [] : undefined;
for (let i = 0; i < columns.value.length; i++) {
const col = columns.value[i];
// Use flex basis width for height calculation as an approximation
// of actual column width (CSS flex layout determines actual width)
const colWidth = columnWidths.value[i] ?? 100;
// Check if custom renderer exists (we can't measure these with pretext)
const hasCustomRenderer = !!(col.cellRenderer || col.slot);
if (hasCustomRenderer) {
// For custom renderers, we use a placeholder height
// Actual height will be measured at runtime via useRuntimeHeightAugment
// For now, use a reasonable minimum
const placeholderHeight = 44; // default row height
maxCellHeight = Math.max(maxCellHeight, placeholderHeight);
cellHeights?.push({
height: placeholderHeight,
isCustomRenderer: true,
});
continue;
}
// Get raw cell value
const cellText = formatCellValue(row, col);
if (!cellText) continue;
// Calculate available width for text (excluding cell padding)
const availableWidth = colWidth - CELL_VERTICAL_PADDING * 2;
if (availableWidth <= 0) continue;
try {
const cellHeight = measureTextHeight(cellText, font, availableWidth, lineHeight);
maxCellHeight = Math.max(maxCellHeight, cellHeight);
cellHeights?.push({
height: cellHeight,
isCustomRenderer: false,
});
} catch {
// Fallback: assume single line
}
}
const totalHeight = maxCellHeight + rowPadding * 2;
return {
height: totalHeight,
isCustomRenderer: false,
cellHeights: cellHeights ?? undefined,
};
});
});
// Total height (sum of all row heights) - useful for virtualizer
const totalHeight = computed(() => rowHeights.value.reduce((sum, entry) => sum + entry.height, 0));
return {
rowHeights,
totalHeight,
};
}