Vue: Создание гибкой таблицы в с использованием компонентов и слотов

от автора

в
Время чтения: 3 мин.

В этой статье мы рассмотрим, как создать гибкий и переиспользуемый компонент таблицы в Vue. Особенность этого подхода заключается в том, что колонки и их слоты для кастомизации данных описываются внутри компонента колонки (MyTableColumn), что делает таблицу более декларативной и удобной для использования.

Что мы будем создавать?

Мы создадим два компонента:

  1. MyTable — компонент таблицы, который отвечает за рендеринг данных и колонок.
  2. MyTableColumn — компонент колонки, который описывает колонку и предоставляет слот для кастомизации отображения данных.

Шаг 1: Компонент таблицы (MyTable.vue)

Компонент MyTable отвечает за рендеринг таблицы. Он собирает колонки из вложенных компонентов MyTableColumn и использует слоты для кастомизации отображения данных.

<template>
  <div>
    <slot /> <!-- добавим слот чтобы таблица могла принимать колонки  -->
    <table>
      <thead>
        <tr>
          <!-- Рендерим заголовки колонок -->
          <th v-for="column in columns" :key="column.prop">
            {{ column.label }}
          </th>
        </tr>
      </thead>
      <tbody>
        <!-- Рендерим строки таблицы -->
        <tr v-for="(row, rowIndex) in data" :key="rowIndex">
          <!-- Рендерим ячейки таблицы -->
          <td v-for="column in columns" :key="column.prop">
            <!-- Используем слот для рендеринга содержимого ячейки -->
            <component :is="column.slot" v-if="column.slot" :row="row" />
            <template v-else>
              {{ row[column.prop] }}
              <!-- Значение по умолчанию, если слот не переопределен -->
            </template>
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</template>

<script>
export default {
  props: {
    data: {
      type: Array,
      required: true,
    },
  },
  data() {
    return {
      columns: [], // Колонки будут собираться из вложенных компонентов MyTableColumn
    }
  },
  methods: {
    // Метод для добавления колонки
    addColumn(column) {
      this.columns.push(column)
    },
  },
  provide() {
    // Передаем метод addColumn в дочерние компоненты через provide/inject
    return {
      addColumn: this.addColumn,
    }
  },
}
</script>

<style scoped>
table {
  width: 100%;
  border-collapse: collapse;
}

th,
td {
  border: 1px solid #ddd;
  padding: 8px;
}

th {
  background-color: #f4f4f4;
}
</style>

Шаг 2: Компонент колонки (MyTableColumn.vue)

Компонент MyTableColumn описывает колонку и предоставляет слот для кастомизации отображения данных. Он передает информацию о колонке и слоте в таблицу через метод addColumn.

<template>
  <!-- Этот компонент не рендерит ничего самостоятельно,
       он только передает данные в родительский компонент таблицы -->
</template>

<script>
export default {
  props: {
    prop: {
      type: String,
      required: true,
    },
    label: {
      type: String,
      required: true,
    },
  },
  inject: ['addColumn'], // Получаем метод addColumn из родительского компонента
  data() {
    return {
      slot: null, // Слот для кастомизации отображения данных
    };
  },
  created() {
    // При создании компонента передаем колонку в таблицу
    this.addColumn({
      prop: this.prop,
      label: this.label,
      slot: this.slot, // Передаем слот в таблицу
    });
  },
  // Метод для регистрации слота
  renderSlot(slot) {
    this.slot = slot;
  },
};
</script>

Шаг 3: Использование в родительском компоненте

Теперь вы можете использовать компоненты MyTable и MyTableColumn в родительском компоненте. Слоты для кастомизации данных описываются внутри компонента колонки.

<template>
  <div>
    <MyTable :data="tableData">
      <!-- Колонка "name" с кастомным слотом -->
      <MyTableColumn prop="name" label="Имя">
        <template v-slot="{ row }">
          <strong>{{ row.name }}</strong>
        </template>
      </MyTableColumn>

      <!-- Колонка "age" с кастомным слотом -->
      <MyTableColumn prop="age" label="Возраст">
        <template v-slot="{ row }">
          <span style="color: blue;">{{ row.age }}</span>
        </template>
      </MyTableColumn>
    </MyTable>
  </div>
</template>

<script>
import MyTable from './MyTable.vue';
import MyTableColumn from './MyTableColumn.vue';

export default {
  components: {
    MyTable,
    MyTableColumn,
  },
  data() {
    return {
      // Данные для таблицы
      tableData: [
        { name: 'Иван', age: 25 },
        { name: 'Мария', age: 30 },
        { name: 'Петр', age: 28 },
      ],
    };
  },
};
</script>

Как это работает?

  1. Компонент MyTableColumn:
    • Описывает колонку (свойства prop и label).
    • Принимает слот для кастомизации отображения данных.
    • Передает колонку и слот в таблицу через метод addColumn.
  2. Компонент MyTable:
    • Собирает колонки и их слоты из вложенных компонентов MyTableColumn.
    • Рендерит таблицу, используя переданные колонки и данные.
    • Если слот для колонки переопределен, рендерит его. В противном случае отображает значение по умолчанию.
  3. Родительский компонент:
    • Определяет данные для таблицы.
    • Описывает колонки с помощью вложенных компонентов MyTableColumn.
    • Переопределяет слоты для кастомизации отображения данных внутри компонента колонки.

Преимущества подхода

  • Декларативность: Колонки и их слоты описываются внутри компонента колонки, что делает код более читаемым и понятным.
  • Гибкость: Вы можете легко кастомизировать отображение данных в ячейках таблицы.
  • Переиспользуемость: Компоненты MyTable и MyTableColumn можно использовать в любом проекте.

Итог

Мы создали гибкий и переиспользуемый компонент таблицы в Vue, где колонки и их слоты описываются внутри компонента колонки. Этот подход делает таблицу более декларативной и удобной для использования. Теперь вы можете легко создавать таблицы с кастомизируемыми ячейками в своих проектах! 🚀


Надеюсь, эта статья была полезной! Если у вас есть вопросы или предложения, оставляйте их в комментариях. 😊


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Сколько будет 10 + 10?