SwTable
Компонент SwTable — динамическая таблица с вложенными заголовками, объединением ячеек (rowspan / colspan), кастомизацией через слоты, подсветкой строк и столбцов при наведении, изменением ширины колонок и фиксацией крайних колонок при горизонтальном скролле.
The SwTable component is a dynamic table with nested headers, cell merging (rowspan / colspan), slot-based customization, row and column hover highlighting, column resizing, and sticky edge columns during horizontal scroll.
Колонки описываются дочерним компонентом SwTableColumn.
Columns are defined with the child SwTableColumn component.
Свойства SwTable / SwTable Properties
| Имя | Тип | По умолчанию | Значения/Описание |
|---|---|---|---|
data | Array | required | Данные таблицы — массив объектов. |
resizable | Boolean | true | Разрешить изменение ширины колонок перетаскиванием края заголовка. |
maxWidth | String | Number | — | Максимальная ширина контейнера таблицы. При переполнении — горизонтальный скролл и активация fixed-колонок. |
События SwTable / SwTable Events
| Имя | Параметрыd | Описание |
|---|---|---|
column-resize | { prop, width } | Срабатывает после изменения ширины колонки (в px). |
Свойства SwTableColumn / SwTableColumn Properties
| Имя | Тип | По умолчанию | Значения / Описание |
|---|---|---|---|
prop | String | — | Ключ поля в объекте строки. Поддерживает вложенные пути: speed.midl. |
label | String | '' | Заголовок колонки. |
width | String | Number | 'auto' | Ширина колонки, например 180 или '180px'. |
height | String | Number | 'auto' | Минимальная высота ячейки заголовка. |
resizable | Boolean | — | Разрешить ресайз конкретной колонки. По умолчанию наследует resizable таблицы. |
minWidth | String | Number | 48 | Минимальная ширина при ресайзе (px). |
fixed | String | — | 'left' | 'right' — фиксация колонки при горизонтальном скролле. |
SwTableColumn без prop используется как групповой заголовок; внутри него задаются дочерние SwTableColumn.
A SwTableColumn without prop is a group header; place child SwTableColumn components inside it.
Подсветка при наведении / Hover highlight
- Row — при наведении на строку в
tbodyподсвечиваются все её ячейки (учитываетсяrowspan). - Column — при наведении на ячейку заголовка подсвечивается весь столбец; для группового заголовка с
colspan— все вложенные колонки.
Стили подсветки заданы в component-sw.css (классы row-hover, col-hover).
Фиксированные колонки / Fixed columns
Фиксация включается, когда одновременно:
1. задан max-width у SwTable;
2. у колонок указан fixed="left" или fixed="right";
3. суммарная ширина таблицы превышает контейнер.
Групповой заголовок фиксируется, если все его дочерние колонки имеют одинаковое значение fixed.
Слоты / Slots
#<prop> — именованный слот для конкретной колонки (приоритет выше cell). Параметры: { row, $index, value }
#cell — универсальный слот для всех колонок (default-слот занят SwTableColumn). Параметры: { row, $index, column, value }
row— весь объект строки данных$index— индекс строки (начиная с 0)column— имя колонки (prop)value— значение ячейки
Пример использования / Example Usage
Базовый пример с вложенными колонками:
<script>
let table = [
{city:{label:'Moscow', rowspan:2},district:'Center',speed:{max:80,min:50,midl:70}},
{city:'Moscow',district:'MRCR',speed:{max:130,min:90,midl:120}},
]
</script>
<style>
.sw-table th, .sw-table td { border: 1px solid #d6d6d6; padding: 6px 10px; }
</style>
<sw-table :data="table">
<sw-table-column label="Label">
<sw-table-column label="City" prop="city"/>
<sw-table-column label="District" prop="district"/>
</sw-table-column>
<sw-table-column label="Speed" prop="speed.midl"/>
</sw-table>
Ресайз колонок:
<script setup>
const users = [
{ name: 'Иван', age: 25 },
{ name: 'Мария', age: 30 },
{ name: 'Петр', age: 35 }
]
function onColumnResize({ prop, width }) {
console.log(prop, width)
}
</script>
<style>
.sw-table th, .sw-table td { border: 1px solid #d6d6d6; padding: 6px 10px; }
</style>
<sw-table :data="users" @column-resize="onColumnResize">
<sw-table-column prop="name" label="Имя" width="180px" />
<sw-table-column prop="age" label="Возраст" width="100px" />
<sw-table-column
prop="actions"
label="Действия"
width="150px"
:resizable="false"
/>
</sw-table>
Фиксированные крайние колонки:
<script setup>
const rows = [
{ id: 1, name: 'Иван', email: 'ivan@example.com', note: 'Примечание 1' },
{ id: 2, name: 'Мария', email: 'maria@example.com', note: 'Примечание 2' },
{ id: 3, name: 'Петр', email: 'petr@example.com', note: 'Примечание 3' }
]
</script>
<style>
.sw-table th, .sw-table td { border: 1px solid #d6d6d6; padding: 6px 10px; }
</style>
<sw-table :data="rows" max-width="520px">
<sw-table-column prop="id" label="ID" width="70px" fixed="left" />
<sw-table-column prop="name" label="Имя" width="160px" fixed="left" />
<sw-table-column prop="email" label="Email" width="200px" />
<sw-table-column prop="note" label="Примечание" width="180px" fixed="right" />
</sw-table>
Пример с v-for для динамических колонок:
<script setup>
import { ref } from 'vue'
const columns = ref([
{ prop: 'name', label: 'Имя', width: '150px' },
{ prop: 'age', label: 'Возраст', width: '100px' },
{ prop: 'email', label: 'Email', width: '200px' }
])
const tableData = ref([
{ name: 'Иван', age: 25, email: 'ivan@example.com' },
{ name: 'Мария', age: 30, email: 'maria@example.com' },
{ name: 'Петр', age: 35, email: 'petr@example.com' }
])
</script>
<style>
.sw-table th, .sw-table td { border: 1px solid #d6d6d6; padding: 6px 10px; }
</style>
<sw-table :data="tableData">
<sw-table-column
v-for="column in columns"
:key="column.prop"
:prop="column.prop"
:label="column.label"
:width="column.width"
/>
</sw-table>
Пример с кастомизацией через слоты:
<script setup>
import { ref } from 'vue'
const users = ref([
{ id: 1, name: 'Иван Петров', age: 25, status: 'active', email: 'ivan@example.com' },
{ id: 2, name: 'Мария Сидорова', age: 30, status: 'inactive', email: 'maria@example.com' },
{ id: 3, name: 'Петр Иванов', age: 35, status: 'active', email: 'petr@example.com' }
])
const deleteUser = (id) => {
console.log('Delete user:', id)
}
</script>
<style>
.sw-table th, .sw-table td { border: 1px solid #d6d6d6; padding: 6px 10px; }
</style>
<sw-table :data="users">
<sw-table-column prop="name" label="Имя" />
<sw-table-column prop="age" label="Возраст" />
<sw-table-column prop="status" label="Статус" />
<sw-table-column prop="actions" label="Действия" width="150px" />
<!-- Именованный слот для конкретной колонки -->
<template #name="{ row, value }">
<strong>{{ value }}</strong>
</template>
<template #age="{ value }">
<span style="color: blue">{{ value }} лет</span>
</template>
<template #status="{ value }">
<span :style="{ color: value === 'active' ? 'green' : 'red' }">
{{ value === 'active' ? '✓ Активен' : '✗ Неактивен' }}
</span>
</template>
<!-- Default слот для колонки actions -->
<template #actions="{ row }">
<button @click="deleteUser(row.id)">Удалить</button>
<a :href="`mailto:${row.email}`">Написать</a>
</template>
</sw-table>
Пример с универсальным слотом cell:
<script setup>
import { ref } from 'vue'
const products = ref([
{ name: 'Товар 1', price: 1000, quantity: 5 },
{ name: 'Товар 2', price: 2500, quantity: 3 },
{ name: 'Товар 3', price: 750, quantity: 10 }
])
</script>
<style>
.sw-table th, .sw-table td { border: 1px solid #d6d6d6; padding: 6px 10px; }
</style>
<sw-table :data="products">
<sw-table-column prop="name" label="Название" />
<sw-table-column prop="price" label="Цена" />
<sw-table-column prop="quantity" label="Количество" />
<template #cell="{ column, value }">
<span v-if="column === 'price'" style="font-weight: bold">
{{ value }} ₽
</span>
<span v-else-if="column === 'quantity' && value < 5" style="color: red">
{{ value }} ⚠️ Мало
</span>
<span v-else>{{ value }}</span>
</template>
</sw-table>
Пример с объединением ячеек (rowspan/colspan):
<script setup>
import { ref } from 'vue'
const complexData = ref([
{
city: { label: 'Москва', rowspan: 2 },
district: 'Центр',
population: 500000
},
{
city: 'Москва', // будет скрыта из-за rowspan
district: 'Север',
population: 300000
},
{
city: { label: 'Общая статистика', colspan: 2 },
population: 800000
}
])
</script>
<style>
.sw-table th, .sw-table td { border: 1px solid #d6d6d6; padding: 6px 10px; }
</style>
<sw-table :data="complexData">
<sw-table-column label="Город" prop="city" />
<sw-table-column label="Район" prop="district" />
<sw-table-column label="Население" prop="population" />
</sw-table>