# 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).

Tabla
<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.

Copyright © 2024-2026 FengMo WenXue