Работа с данными в таблицах

SvelteKit предоставляет мощный каркас для построения динамических веб-приложений, а при работе с табличными данными особое внимание уделяется управлению состоянием, рендерингу и интерактивности. UI-библиотеки, совместимые с SvelteKit, позволяют создавать насыщенные таблицы с сортировкой, фильтрацией и пагинацией без избыточного кода.


Основные подходы к отображению таблиц

  1. Статическая таблица Для простых случаев можно использовать стандартный компонент <table> с синтаксисом Svelte:
<script>
  let users = [
    { id: 1, name: "Иван", age: 28 },
    { id: 2, name: "Мария", age: 34 },
    { id: 3, name: "Пётр", age: 23 }
  ];
</script>

<table>
  <thead>
    <tr>
      <th>ID</th>
      <th>Имя</th>
      <th>Возраст</th>
    </tr>
  </thead>
  <tbody>
    {#each users as user}
      <tr>
        <td>{user.id}</td>
        <td>{user.name}</td>
        <td>{user.age}</td>
      </tr>
    {/each}
  </tbody>
</table>

Особенности:

  • Легко интегрируется с реактивными переменными.
  • Подходит для небольших массивов данных.
  • Не требует внешних библиотек, но ограничен в интерактивности.

Сортировка данных

Для динамической сортировки данных в таблице используют реактивные переменные и методы массивов JavaScript. Пример сортировки по имени:

<script>
  let sortAsc = true;

  function sortByName() {
    users = [...users].sort((a, b) => {
      if (a.name > b.name) return sortAsc ? 1 : -1;
      if (a.name < b.name) return sortAsc ? -1 : 1;
      return 0;
    });
    sortAsc = !sortAsc;
  }
</script>

<button on:click={sortByName}>Сортировать по имени</button>

<table>
  <thead>
    <tr>
      <th>ID</th>
      <th>Имя</th>
      <th>Возраст</th>
    </tr>
  </thead>
  <tbody>
    {#each users as user}
      <tr>
        <td>{user.id}</td>
        <td>{user.name}</td>
        <td>{user.age}</td>
      </tr>
    {/each}
  </tbody>
</table>

Ключевой момент: сортировка в SvelteKit требует иммутабельного обновления массива, чтобы триггерить реактивность.


Фильтрация данных

Фильтрация обычно реализуется через ввод текста или селекторы и реактивные выражения. Пример фильтрации по имени:

<script>
  let filter = "";

  $: filteredUsers = users.filter(user => 
    user.name.toLowerCase().includes(filter.toLowerCase())
  );
</script>

<input placeholder="Фильтр по имени" bind:value={filter} />

<table>
  <thead>
    <tr>
      <th>ID</th>
      <th>Имя</th>
      <th>Возраст</th>
    </tr>
  </thead>
  <tbody>
    {#each filteredUsers as user}
      <tr>
        <td>{user.id}</td>
        <td>{user.name}</td>
        <td>{user.age}</td>
      </tr>
    {/each}
  </tbody>
</table>

Выделение: использование $: позволяет автоматически пересчитывать отображаемый массив при изменении фильтра.


Пагинация больших наборов данных

Для работы с большими таблицами удобно делить данные на страницы. Пример с простейшей пагинацией:

<script>
  let currentPage = 1;
  const pageSize = 2;

  $: totalPages = Math.ceil(users.length / pageSize);
  $: paginatedUsers = users.slice((currentPage - 1) * pageSize, currentPage * pageSize);

  function nextPage() {
    if (currentPage < totalPages) currentPage++;
  }

  function prevPage() {
    if (currentPage > 1) currentPage--;
  }
</script>

<table>
  <thead>
    <tr>
      <th>ID</th>
      <th>Имя</th>
      <th>Возраст</th>
    </tr>
  </thead>
  <tbody>
    {#each paginatedUsers as user}
      <tr>
        <td>{user.id}</td>
        <td>{user.name}</td>
        <td>{user.age}</td>
      </tr>
    {/each}
  </tbody>
</table>

<button on:click={prevPage} disabled={currentPage === 1}>Назад</button>
<button on:click={nextPage} disabled={currentPage === totalPages}>Вперед</button>

Важно: правильное управление индексами и иммутабельность данных критичны для корректной работы пагинации.


Интеграция с Svelte UI-библиотеками

Современные UI-библиотеки для SvelteKit, такие как Svelte Material UI, SvelteStrap, Flowbite Svelte, предоставляют готовые компоненты таблиц с расширенной функциональностью:

  • Сортировка по столбцам: встроенные кликабельные заголовки.
  • Фильтры и поиск: легко подключаемые input-компоненты.
  • Пагинация и скролл: поддержка виртуализации для тысяч записей.
  • Стилизация: встроенные темы и адаптивность под мобильные устройства.

Пример использования SMUI DataTable:

<script>
  import { DataTable, DataTableHead, DataTableBody, DataTableRow, DataTableCell } from '@smui/data-table';
</script>

<DataTable>
  <DataTableHead>
    <DataTableRow>
      <DataTableCell>ID</DataTableCell>
      <DataTableCell>Имя</DataTableCell>
      <DataTableCell>Возраст</DataTableCell>
    </DataTableRow>
  </DataTableHead>
  <DataTableBody>
    {#each users as user}
      <DataTableRow>
        <DataTableCell>{user.id}</DataTableCell>
        <DataTableCell>{user.name}</DataTableCell>
        <DataTableCell>{user.age}</DataTableCell>
      </DataTableRow>
    {/each}
  </DataTableBody>
</DataTable>

Преимущество: минимизация ручного кода и встроенная поддержка анимаций и событий.


Реактивность и оптимизация

  • Реактивные выражения $: позволяют автоматически обновлять отображение при изменении данных.
  • Иммутабельные операции (map, filter, slice) гарантируют триггер обновления UI.
  • Для очень больших таблиц рекомендуется использовать виртуализацию (svelte-virtual-list) для экономии памяти и производительности.
  • Сортировка и фильтрация должны происходить на уровне данных, а не только на уровне DOM, чтобы уменьшить нагрузку при больших массивах.

Интерактивные элементы внутри таблицы

SvelteKit поддерживает включение кнопок, чекбоксов, селектов прямо в ячейки таблицы:

<table>
  <thead>
    <tr>
      <th>Имя</th>
      <th>Действие</th>
    </tr>
  </thead>
  <tbody>
    {#each users as user}
      <tr>
        <td>{user.name}</td>
        <td>
          <button on:click={() => alert(`Выбрано: ${user.name}`)}>Выбрать</button>
        </td>
      </tr>
    {/each}
  </tbody>
</table>

Особенность: события внутри ячеек легко связываются с состоянием компонента, что делает таблицы полностью интерактивными.


Эти методы позволяют строить мощные таблицы, которые динамически реагируют на изменения данных, поддерживают фильтрацию, сортировку, пагинацию и интерактивные элементы, используя чистый SvelteKit и UI-библиотеки.