Appearance
BaseTable
재사용 가능한 기본 테이블 컴포넌트입니다. 정렬, 페이징, 컬럼 크기 조정, 행 선택 등의 기본 테이블 기능을 제공합니다.
개요
BaseTable은 PagingTable의 핵심 기능을 담당하는 컴포넌트로, 대용량 데이터 테이블을 효율적으로 렌더링하고 사용자 인터랙션을 처리합니다. 컬럼 설정 저장, 동적 크기 조정, 스켈레톤 로딩 등의 고급 기능을 포함합니다.
주요 특징
- 📊 대용량 데이터 처리: 가상화를 통한 효율적인 렌더링
- 🔧 컬럼 커스터마이징: 크기 조정, 표시/숨김, 순서 변경
- 🔍 정렬 및 검색: 다중 컬럼 정렬과 행 검색 지원
- 💾 설정 저장: 로컬 스토리지를 통한 사용자 설정 유지
- ⚡ 스켈레톤 로딩: 데이터 로딩 중 스켈레톤 UI 표시
- ✅ 행 선택: 단일/다중 행 선택 지원
Props Interface
typescript
interface PagingTableProps<T extends Record<string, unknown>> {
/** 테이블 고유 식별자 (설정 저장용) */
alias: string;
/** 테이블 너비 */
width: number;
/** 테이블 높이 */
height: number;
/** 페이지당 표시할 행 수 */
displayCount: number;
/** 컬럼 정의 배열 */
columns: PagingTableColumn[];
/** 테이블 데이터 배열 */
rows: PagingTableRow<T>[];
/** 행 높이 (기본값: 40px) */
rowHeight?: number;
/** 컬럼별 최대값 맵 (프로그레스 바 등에 사용) */
maxMap?: Record<string, number>;
/** 현재 정렬 키 */
sortKey?: string;
/** 현재 정렬 순서 */
sortOrder?: PagingTableSortOrder;
/** 정렬 로딩 상태 */
sortLoading?: boolean;
/** 스켈레톤 로딩 사용 여부 (기본값: true) */
useSkeleton?: boolean;
/** 행 선택 기능 사용 여부 (기본값: true) */
useSelect?: boolean;
/** 찾을 행 ID (해당 행으로 자동 스크롤) */
foundRowId?: string;
/** 선택된 행 ID 배열 */
selectedRowIds?: string[];
}
컬럼 정의
typescript
interface PagingTableColumn {
/** 컬럼 키 (데이터 객체의 속성 이름) */
key: string;
/** 컬럼 표시 이름 */
name: string;
/** 셀 타입 */
type: PagingTableCellType;
/** 컬럼 비율 (0-1, 전체 너비 대비) */
rate?: number;
/** 정렬 가능 여부 */
sortable?: boolean;
/** 표시 여부 */
visible?: boolean;
/** 셀 색상 */
color?: string;
}
행 데이터 구조
typescript
interface PagingTableRow<T> {
/** 실제 데이터 객체 */
data: T;
/** 행 고유 식별자 */
id: string;
}
Events
typescript
interface PagingTableEmits<T> {
/** 컬럼 정렬 시 발생 */
'sort': [key: string, order: PagingTableSortOrder];
/** 행 선택 시 발생 */
'select': [id: string, row?: PagingTableRow<T>];
}
기본 사용법
vue
<template>
<BaseTable
alias="transaction-table"
:width="800"
:height="600"
:display-count="50"
:columns="tableColumns"
:rows="tableRows"
:sort-key="sortKey"
:sort-order="sortOrder"
:selected-row-ids="selectedRows"
@sort="handleSort"
@select="handleRowSelect"
>
<template #information>
<div class="table-info">
총 {{ tableRows.length }}개 항목
</div>
</template>
<template #tools="{ columns, updateColumns, resetSettings }">
<div class="table-tools">
<button @click="resetSettings">설정 초기화</button>
<button @click="exportData">데이터 내보내기</button>
</div>
</template>
<template #row="{ row, column, value }">
<!-- 커스텀 셀 렌더링 -->
<span v-if="column.key === 'status'" :class="`status-${value}`">
{{ getStatusText(value) }}
</span>
<span v-else>{{ value }}</span>
</template>
</BaseTable>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { BaseTable } from '@jennifersoft/apm-components';
import type {
PagingTableColumn,
PagingTableRow,
PagingTableSortOrder
} from '@jennifersoft/apm-components';
interface TransactionData {
id: string;
timestamp: number;
method: string;
uri: string;
responseTime: number;
status: number;
errorCount: number;
}
const tableColumns = ref<PagingTableColumn[]>([
{
key: 'timestamp',
name: '시간',
type: PagingTableCellType.DATETIME,
rate: 0.15,
sortable: true
},
{
key: 'method',
name: 'Method',
type: PagingTableCellType.TEXT,
rate: 0.1,
sortable: true
},
{
key: 'uri',
name: 'URI',
type: PagingTableCellType.TEXT,
rate: 0.4,
sortable: true
},
{
key: 'responseTime',
name: '응답시간',
type: PagingTableCellType.NUMBER,
rate: 0.15,
sortable: true
},
{
key: 'status',
name: '상태',
type: PagingTableCellType.CUSTOM,
rate: 0.1,
sortable: true
},
{
key: 'errorCount',
name: '에러수',
type: PagingTableCellType.NUMBER,
rate: 0.1,
sortable: true
}
]);
const tableRows = ref<PagingTableRow<TransactionData>[]>([]);
const sortKey = ref<string>('timestamp');
const sortOrder = ref<PagingTableSortOrder>(PagingTableSortOrder.DESC);
const selectedRows = ref<string[]>([]);
const handleSort = (key: string, order: PagingTableSortOrder) => {
sortKey.value = key;
sortOrder.value = order;
// 실제 정렬 로직 구현
sortTableData(key, order);
};
const handleRowSelect = (id: string, row?: PagingTableRow<TransactionData>) => {
if (selectedRows.value.includes(id)) {
selectedRows.value = selectedRows.value.filter(rowId => rowId !== id);
} else {
selectedRows.value.push(id);
}
};
const getStatusText = (status: number): string => {
if (status >= 200 && status < 300) return '성공';
if (status >= 400 && status < 500) return '클라이언트 오류';
if (status >= 500) return '서버 오류';
return '알 수 없음';
};
</script>
컬럼 타입
BaseTable은 다양한 셀 타입을 지원합니다:
typescript
enum PagingTableCellType {
TEXT = 'TEXT', // 일반 텍스트
NUMBER = 'NUMBER', // 숫자 (천 단위 구분자 포함)
DATETIME = 'DATETIME', // 날짜/시간
PROGRESS = 'PROGRESS', // 프로그레스 바
CUSTOM = 'CUSTOM', // 커스텀 렌더링
LINK = 'LINK', // 링크
BADGE = 'BADGE', // 배지
CHART = 'CHART' // 미니 차트
}
설정 저장 및 복원
BaseTable은 사용자 설정을 자동으로 로컬 스토리지에 저장합니다:
typescript
// 저장되는 설정들
interface TableSettings {
columnRates: number[]; // 컬럼 너비 비율
visibleColumns: string[]; // 표시되는 컬럼 키
sortKey: string; // 마지막 정렬 키
sortOrder: PagingTableSortOrder; // 마지막 정렬 순서
}
// 스토리지 키 형식
const storageKeys = {
columnRates: `COLUMN_RATES#${alias}`,
visibleColumns: `VISIBLE_COLUMNS#${alias}`,
sortSettings: `SORT_SETTINGS#${alias}`
};
슬롯 활용
information 슬롯
vue
<template #information>
<div class="table-summary">
<span class="total-count">총 {{ totalCount }}개</span>
<span class="selected-count" v-if="selectedCount > 0">
{{ selectedCount }}개 선택됨
</span>
<span class="filter-status" v-if="isFiltered">
필터 적용됨
</span>
</div>
</template>
tools 슬롯
vue
<template #tools="{ columns, updateColumns, resetSettings }">
<div class="table-toolbar">
<ColumnManager
:columns="columns"
@update="updateColumns"
/>
<ExportButton
:data="tableRows"
:columns="columns"
/>
<button @click="resetSettings">
설정 초기화
</button>
</div>
</template>
row 슬롯
vue
<template #row="{ row, column, value, cellWidth }">
<!-- 커스텀 셀 렌더링 -->
<div
v-if="column.type === 'CUSTOM'"
:style="{ width: cellWidth + 'px' }"
>
<StatusBadge :status="value" />
</div>
<!-- 기본 렌더링 -->
<span v-else>{{ formatCellValue(value, column.type) }}</span>
</template>
의존성
@jennifersoft/vue-components-v2
: ProgressIndicator 컴포넌트- Vue 3: Composition API와 Generic Props 지원
- 로컬 스토리지: 사용자 설정 저장
브라우저 지원
- Chrome 80+
- Firefox 75+
- Safari 13+
- Edge 80+
알려진 제한사항
- 메모리 사용량: 대용량 데이터 (10,000+ 행)에서 메모리 사용량 증가
- 가상화: 현재 수직 가상화만 지원 (수평 가상화 미지원)
- 컬럼 순서: 동적 컬럼 순서 변경 미지원 (향후 버전에서 지원 예정)