Слой абстракции над Element Plus

Element Plus предоставляет богатый набор компонентов для разработки интерфейсов на Vue 3, однако при работе с крупными проектами часто возникает необходимость создать собственный слой абстракции. Такой слой позволяет централизовать настройку компонентов, стандартизировать стили и поведение, а также упростить поддержку приложения.


Основные цели слоя абстракции

  1. Унификация внешнего вида и поведения компонентов Каждый компонент может иметь множество настроек и пропсов. Создание оберток позволяет определить единый стиль для кнопок, форм, таблиц, модальных окон и других элементов, избегая повторения кода.

  2. Инкапсуляция бизнес-логики Компоненты Element Plus часто требуют дополнительной логики: обработка событий, валидация данных, работа с API. Обертки позволяют вынести эту логику из компонентов интерфейса в отдельный слой.

  3. Упрощение миграций и обновлений При обновлении Element Plus или смене дизайна достаточно изменить обертку, не трогая весь проект. Это снижает риск ошибок и ускоряет разработку.


Пример структуры абстракции

/components
 ├─ ui
 │   ├─ UiButton.vue
 │   ├─ UiInput.vue
 │   ├─ UiSelect.vue
 │   └─ UiTable.vue
 ├─ layout
 │   ├─ Header.vue
 │   ├─ Sidebar.vue
 │   └─ Footer.vue
 └─ modal
     ├─ ConfirmModal.vue
     └─ FormModal.vue
  • Папка ui содержит универсальные элементы интерфейса.
  • Папка layout объединяет компоненты разметки страницы.
  • Папка modal отвечает за модальные окна с типовыми сценариями использования.

Создание обертки для кнопки

<template>
  <el-button
    :type="type"
    :size="size"
    :loading="loading"
    :disabled="disabled"
    @click="$emit('click', $event)"
  >
    <slot></slot>
  </el-button>
</template>

<script setup>
import { defineProps, defineEmits } from 'vue';

const props = defineProps({
  type: { type: String, default: 'primary' },
  size: { type: String, default: 'medium' },
  loading: { type: Boolean, default: false },
  disabled: { type: Boolean, default: false }
});

const emit = defineEmits(['click']);
</script>

Преимущества такой обертки:

  • Стандартизированные тип и размер кнопок по всему проекту.
  • Возможность добавления глобальных обработчиков событий, трекинга или аналитики.
  • Простое расширение функциональности без изменения кода во всех местах использования.

Абстракция форм и валидации

Element Plus предоставляет ElForm и ElFormItem, но логика валидации часто повторяется. Можно создать обертку, которая автоматически подключает стандартные правила.

<template>
  <el-form :model="model" :rules="rules" ref="formRef" label-width="120px">
    <slot></slot>
  </el-form>
</template>

<script setup>
import { ref, defineProps } from 'vue';

const props = defineProps({
  model: { type: Object, required: true },
  rules: { type: Object, default: () => ({}) }
});

const formRef = ref(null);

const validate = async () => {
  try {
    await formRef.value.validate();
    return true;
  } catch {
    return false;
  }
};

export { validate, formRef };
</script>

Возможности:

  • Унифицированная валидация форм во всех компонентах.
  • Централизованное управление ошибками и подсказками.
  • Легкая интеграция с сервисами API и обработкой ошибок на сервере.

Таблицы с оберткой

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

<template>
  <el-table :data="data" border>
    <slot></slot>
  </el-table>
  <el-pagination
    v-if="pagination"
    :current-page="pagination.page"
    :page-size="pagination.size"
    :total="pagination.total"
    @current-change="$emit('page-change', $event)"
  />
</template>

<script setup>
import { defineProps, defineEmits } from 'vue';

const props = defineProps({
  data: { type: Array, default: () => [] },
  pagination: { type: Object, default: null }
});

const emit = defineEmits(['page-change']);
</script>

Преимущества:

  • Автоматическая работа с пагинацией без повторения кода.
  • Возможность централизованного управления таблицами с фильтрами, сортировкой и стилизацией.
  • Легкая кастомизация отображения колонок через слоты.

Модальные окна и уведомления

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

import { ElMessage, ElMessageBox } from 'element-plus';

export const notifySuccess = (msg) => {
  ElMessage({
    message: msg,
    type: 'success',
    duration: 3000
  });
};

export const confirmDialog = async (msg) => {
  try {
    await ElMessageBox.confirm(msg, 'Подтверждение', {
      confirmButtonText: 'Да',
      cancelButtonText: 'Нет',
      type: 'warning'
    });
    return true;
  } catch {
    return false;
  }
};

Эффекты:

  • Снижение дублирования кода для уведомлений.
  • Возможность централизованного изменения внешнего вида всех модальных окон.
  • Поддержка локализации и кастомных анимаций в одном месте.

Рекомендации по созданию слоя абстракции

  1. Использовать слоты для гибкости Позволяет сохранять возможность кастомизации компонентов при сохранении базовых настроек.

  2. Выносить повторяющуюся логику в композиционные функции Например, useFormValidation, useTablePagination, useNotification. Это упрощает повторное использование и тестирование.

  3. Централизованно управлять стилями Через SCSS-переменные или глобальные классы, чтобы внешний вид компонентов оставался единым.

  4. Соблюдать единый паттерн именования Например, все обертки начинаются с Ui, модальные окна — с Modal. Это повышает читаемость и поддерживаемость проекта.


Слой абстракции над Element Plus повышает масштабируемость проекта, облегчает поддержку интерфейса и делает код более предсказуемым. Правильная организация оберток и функций позволяет создавать комплексные приложения без потери контроля над стилем и логикой компонентов.