# Tabla
Tabla de datos. Admite ordenación (controlada / no controlada), filtrado de columnas, arrastre del ancho de columnas, encabezados multinivel (anidamiento infinito mediante children) y columnas fijas; al definir height se activa el desplazamiento virtual (rowHeight debe coincidir con la altura real de las filas).
<template>
<div style="max-width: 760px">
<p class="demo-note">size="small" + maxHeight + orden inicial (defaultSortProp/defaultSortOrder) + filtrado</p>
<LhTable
:data="rows"
:columns="columns"
size="small"
stripe
border
:max-height="200"
row-key="name"
default-sort-prop="dynasty"
default-sort-order="asc"
:default-filtered-values="{ dynasty: ['Song'] }"
>
<template #price="{ value }">
<span style="color: var(--lh-primary-color); font-weight: 600">{{ value }}</span>
</template>
</LhTable>
<p class="demo-note">La columna «Dinastía» está en orden ascendente por defecto y prefiltrada por «Song»; el botón de filtrado del encabezado permite cambiar la condición.</p>
<p class="demo-note" style="margin-top: 16px">Encabezados anidados (children) + arrastre del ancho con resizable + formatter + sorter personalizado</p>
<LhTable :data="rows2" :columns="groupColumns" border :height="180" :row-height="40" :sorter="dynastySorter">
<template #price="{ value }">
<span style="color: var(--lh-primary-color); font-weight: 600">{{ value }}</span>
</template>
</LhTable>
<p class="demo-note">La columna «Procedencia» se formatea con formatter como «Colección imperial»/«Colección privada»; la columna «Valoración» permite cambiar el ancho arrastrando (resizable).</p>
</div>
</template>
<script>
export default {
data: () => ({
rows: [
{ name: 'Viaje por las montañas y los arroyos', dynasty: 'Song', price: 1800 },
{ name: 'Morada en las montañas Fuchun', dynasty: 'Yuan', price: 2600 },
{ name: 'Mil li de ríos y montañas', dynasty: 'Song', price: 3200 },
{ name: 'A orillas del río durante el festival Qingming', dynasty: 'Song', price: 1500 },
{ name: 'El banquete nocturno de Han Xizai', dynasty: 'Cinco dinastías', price: 2100 },
],
rows2: [
{ name: 'Viaje por las montañas y los arroyos', dynasty: 'Song', provenance: 'Colección imperial', price: 1800 },
{ name: 'Morada en las montañas Fuchun', dynasty: 'Yuan', provenance: 'Colección imperial', price: 2600 },
{ name: 'A orillas del río durante el festival Qingming', dynasty: 'Song', provenance: 'Colección imperial', price: 1500 },
{ name: 'Blanco resplandeciente en la noche', dynasty: 'Tang', provenance: 'Colección privada', price: 980 },
],
columns: [
{ prop: 'name', label: 'Obra', width: 160 },
{
prop: 'dynasty',
label: 'Dinastía',
width: 120,
sortable: true,
filters: [
{ text: 'Song', value: 'Song' },
{ text: 'Yuan', value: 'Yuan' },
{ text: 'Cinco dinastías', value: 'Cinco dinastías' },
],
},
{ prop: 'price', label: 'Valoración (decenas de miles)', width: 140, align: 'right', slot: 'price' },
],
groupColumns: [
{
label: 'Información de la pieza',
children: [
{ prop: 'name', label: 'Obra', width: 150 },
{
prop: 'provenance',
label: 'Procedencia',
width: 100,
formatter: (r) => (r.provenance === 'Colección imperial' ? 'Colección imperial' : 'Colección privada'),
},
],
},
{
label: 'Valoración',
children: [
{ prop: 'dynasty', label: 'Dinastía', width: 90, sortable: true },
{ prop: 'price', label: 'Valoración (decenas de miles)', width: 130, align: 'right', resizable: true, slot: 'price' },
],
},
],
}),
methods: {
dynastySorter(a, b) {
const order = ['Tang', 'Cinco dinastías', 'Song', 'Yuan']
return order.indexOf(String(a.dynasty)) - order.indexOf(String(b.dynasty))
},
},
}
</script>
# Props
| Prop | Descripción | Tipo | Predeterminado |
|---|---|---|---|
| data | Datos de las filas | LhTableRow[] | [] |
| columns | Configuración de las columnas | LhTableColumn[] | [] |
| height | Altura del cuerpo de la tabla (al definirla se activa el desplazamiento virtual; un número se interpreta como px) | number \| string | — |
| maxHeight | Altura máxima en el modo no virtual | number \| string | — |
| rowHeight | Altura de fila del desplazamiento virtual (debe coincidir con la altura real) | number | — |
| stripe / border | Filas alternas / bordes de las celdas | boolean | false |
| size | Tamaño | 'small' \| 'default' \| 'large' | 'default' |
| rowKey | Nombre del campo clave de la fila | string | — |
| defaultSortProp / defaultSortOrder | Columna / dirección de la ordenación inicial | string / LhTableSortOrder | — |
| sorter | Función de ordenación personalizada | (a, b) => number | — |
| resizable | Activa el arrastre del ancho de columnas (requiere además la configuración de resizable a nivel de columna y que la columna tenga un width numérico) | boolean | false |
| defaultFilteredValues | Estado de filtrado inicial (no controlado; la clave es el prop de la columna) | Record<string, (string \| number)[]> | — |
| filteredValues | Estado de filtrado controlado (:filtered-values.sync) | Record<string, (string \| number)[]> | — |
| sx | Prop abreviada de maquetación | — | — |
# Events
sortChange ({ prop, order })、filterChange ({ prop, values })、columnResize ({ prop, width })、update:filteredValues、rowClick (row, index)
# Slots
| Slot | Descripción |
|---|---|
<nombre del slot de columna> | Celda personalizada; parámetros de alcance { row, column, index, value } (la columna se designa con column.slot) |
| empty | Contenido cuando no hay datos (predeterminado: «暂无数据») |
# Accesibilidad
Las filas del encabezado usan role="row" y las columnas ordenables, aria-sort; las filas del cuerpo, role="row".
El panel de filtrado usa role="menu"; el tirador de redimensionado lleva aria-label y tabindex, y admite el ajuste con las teclas de flecha izquierda y derecha.
← Calendario Árbol →
Copyright © 2024-2026 FengMo WenXue