Table Component Design Documentation
Overview
The Table component is a core component in this library used for displaying tabular data. It adheres to the library's consistent design philosophy of "Separation of Concerns" and "Logic Abstraction." Through core components like table.vue and tableColumn.vue, it provides a complete and user-friendly table solution.
The Table component focuses on handling data display, interaction, and style management for tables, offering users a powerful and flexible table management feature. It supports basic tables, tree tables, row selection, row expansion, and other functionalities, effectively enhancing the user experience when working with structured data.
Design Philosophy
Layered Architecture
The Table component is strictly designed with a three-layer architecture:
- Structure Layer (
table.vue,tableColumn.vue) - Responsible for the component's DOM structure and basic layout. - Logic Layer (
table.ts,tableComputed.ts) - Handles complex reactive computations and interaction logic. - Presentation Layer (
table.scss) - Defines the component's visual presentation and style rules.
Logic Abstraction
The Table component abstracts complex logic into core functions:
useTableComputed- Handles core table logic.flattenTreeData- Handles flattening of tree data.toggleRowExpansion- Handles row expand/collapse logic.toggleRowSelection- Handles row selection logic.
This design allows the component itself to simply declare the required logic, while the specific computations are handled by the logic functions.
Core Feature Design
Structured Props Design
The props design for the Table component is clean and straightforward:
export const tableProps = {
/** Table data */
data: {
type: Array as () => Record<string, unknown>[],
default: () => []
},
/** Column definitions */
columns: {
type: Array as () => TableColumnProps[],
default: () => []
},
/** Selected rows */
modelValue: {
type: [Array, String] as PropType<string[] | number[] | string>,
default: () => []
},
/** Table width */
width: {
type: String,
default: ''
},
/** Table height */
height: {
type: String,
default: ''
},
/** Header background color */
headerBackgroundColor: {
type: String,
default: ''
},
/** Header text color */
headerTextColor: {
type: String,
default: ''
},
/** Stripe background color */
stripe: {
type: String,
default: ''
},
/** Border color */
borderColor: {
type: String,
default: ''
},
/** Body background color */
bodyBackgroundColor: {
type: String,
default: ''
},
/** Hover background color */
hoverBackgroundColor: {
type: String,
default: ''
},
/** Body text color */
bodyTextColor: {
type: String,
default: ''
},
/** Row unique identifier key */
rowKey: {
type: String,
default: 'id'
},
/** Tree structure configuration */
treeProps: {
type: Object as () => {
children?: string;
hasChildren?: string;
},
default: () => ({
children: 'children',
hasChildren: 'hasChildren'
})
},
/** Tree indent */
indent: {
type: Number,
default: 16
},
/** Alignment */
align: {
type: String as PropType<'left' | 'center' | 'right'>,
default: 'left'
},
/** Header alignment */
headerAlign: {
type: String as PropType<'left' | 'center' | 'right'>,
default: ''
},
/** Body alignment */
bodyAlign: {
type: String as PropType<'left' | 'center' | 'right'>,
default: ''
}
}Parameter Descriptions:
- data: The data source for the table.
- columns: Column definition configuration.
- modelValue: Used for two-way binding of selected rows.
- stripe: Sets the stripe background color.
- treeProps: Configures the child node field for tree tables.
- indent: Sets the indent amount for tree tables.
- Column Definition Design
Column Definition Design
Props design for the TableColumn component:
export const tableColumnProps = {
/** Column property */
prop: {
type: String,
required: true
},
/** Column header label */
label: {
type: String,
default: undefined
},
/** Column width */
width: {
type: String,
default: ''
},
/** Fixed column */
fixed: {
type: String as PropType<'left' | 'right'>,
default: undefined
},
/** Whether sortable */
sortable: {
type: Boolean,
default: false
},
/** Alignment */
align: {
type: String as PropType<'left' | 'right' | 'center'>,
default: ''
},
/** Header alignment */
headerAlign: {
type: String as PropType<'left' | 'right' | 'center'>,
default: ''
},
/** Body alignment */
bodyAlign: {
type: String as PropType<'left' | 'right' | 'center'>,
default: ''
},
/** Column type */
type: {
type: String,
default: ''
}
}Supported Column Types:
- Normal Data Column: Defined via prop and label.
- Selection Column: Defined via type="selection".
- Tree Column: Defined via prop and tree data structure.
Style System Design
CSS Variable Control
The Table component achieves style control through CSS variables:
- --table-border-color - Table border color.
- --hover-bg-color - Row hover background color.
Layout System
The Table component supports flexible layout control:
- Table Layout - Uses table-layout: auto for self-adaptation.
- Column Width Control - Controls column width via the width property.
- Alignment - Supports global and column-level alignment configuration.
- Tree Structure - Displays hierarchical relationships via indentation.
State Styles
The Table component provides corresponding styles for different states:
- Default State - Standard table style.
- Hover State - Background color change on row hover.
- Stripe State - Alternating row background colors.
- Expanded State - Expand/collapse state for tree tables.
- Selected State - Row selection state.
Component Structure Design
Overall Structure
The overall structure of the Table component is as follows:
<div class="my-table" :style="{ '--table-border-color': props.borderColor, ...tableStyle }">
<table>
<thead :style="headerStyle">
<tr>
<th v-for="column in columnsWithWidth" :key="column.prop" :style="getColumnStyle(column, 'header')">
<!-- Header content -->
</th>
</tr>
</thead>
<tbody :style="bodyStyle">
<tr v-for="(item, index) in flatTableData" :key="getRowKey(item.row)"
:style="index % 2 === 1 ? { backgroundColor: props.stripe } : {}">
<td v-for="column in columnsWithWidth" :key="column.prop" :style="getColumnStyle(column, 'body')">
<!-- Cell content -->
</td>
</tr>
</tbody>
</table>
<div class="pagination-container">
<slot name="pagination"></slot>
</div>
</div>Component Hierarchy
The Table component consists of several main parts:
- Container - .my-table - Wraps the entire table component.
- Header - thead - Table header area.
- Body - tbody - Table body area.
- Row - tr - Single table row.
- Cell - td - Single cell.
- Pagination Container - .pagination-container - Placeholder for pagination component. The TableColumn component serves as a declarative component:
<MYTableColumn prop="name" label="name" width="150px" />Interaction Design
Tree Data Handling
The Table component processes tree data via flattenTreeData:
const flattenTreeData = (
data: RowRecord[],
level = 0,
parent: RowRecord | null = null
): Array<{ row: RowRecord; level: number; parent: RowRecord | null; isLeaf: boolean }> => {
const result: Array<{ row: RowRecord; level: number; parent: RowRecord | null; isLeaf: boolean }> = [];
data.forEach((item) => {
const children = getChildren(item);
const isLeaf = children.length === 0;
result.push({
row: item,
level,
parent,
isLeaf,
});
if (!isLeaf && isRowExpanded(item)) {
result.push(...flattenTreeData(children, level + 1, item));
}
});
return result;
};Row Expand/Collapse
The Table component implements row expand/collapse via toggleRowExpansion:
const toggleRowExpansion = (row: RowRecord, expanded?: boolean) => {
const key = getRowKey(row);
const index = expandedRowKeys.value.indexOf(key);
const isExpanded = index !== -1;
if (expanded === undefined) expanded = !isExpanded;
if (expanded && !isExpanded) {
expandedRowKeys.value.push(key);
} else if (!expanded && isExpanded) {
expandedRowKeys.value.splice(index, 1);
}
};Row Selection Feature
The Table component implements row selection via toggleRowSelection
const toggleRowSelection = (row: RowRecord) => {
const key = getRowKey(row);
const index = selectedRows.value.findIndex((s) => getRowKey(s as RowRecord) === key);
if (index > -1) {
selectedRows.value.splice(index, 1);
} else {
selectedRows.value.push(row);
}
emitUpdate();
};Event System:
- update:modelValue: Triggered when selected rows change.
- selection-change: Triggered when selected rows change.
Extensibility Design
The Table component offers excellent extensibility:
- Column Definition: Flexibly define columns via the columns property and tableColumn component.
- Slot Support: Customize cell content via the slot mechanism.vue
<MYTable :data="data" :columns="columns"> <template #name="{ row }"> <span style="color: red">{{ row.name }}</span> </template> </MYTable> - Style Customization: Customize table styles via various color properties.
- Tree Structure: Support tree tables via treeProps and indent.
- Pagination Integration: Integrate pagination components via the pagination slot.
Style Details
The Table component features the following style handling characteristics:
- Responsive Design: Supports flexible layout adaptation.
- Consistency: Maintains style consistency with other library components.
- Accessibility Design: Ensures keyboard navigation and screen reader friendliness.
- State Feedback: Provides clear visual feedback (e.g., hover state, selected state).
- Animation Effects: Smooth transition effects for expand/collapse.
Performance Optimization
Performance is optimized through:
- Caching table data processing results using computed properties.
- Moving complex logic into independent functions.
- Avoiding unnecessary re-renders.
- Leveraging Vue 3 Composition API for runtime efficiency.
- Rendering tree table child nodes on demand.
- Dynamically adjusting styles using CSS variables.
Design Value
The Table component embodies the design philosophy of our component library:
- Separation of Concerns: Complete decoupling of structure, style, and logic.
- High Reusability: Abstracting common logic via functions.
- Ease of Maintenance: Clear code structure and naming conventions.
- Strong Extensibility: Support for rich customization options.
- Consistency: Maintains a consistent design language with other components like DataGrid and ListView.