Wrapper компоненты

Wrapper-компоненты в Element Plus представляют собой оболочки над стандартными UI-компонентами, позволяющие расширять их функциональность, унифицировать стили и упрощать повторное использование в проектах. Они создаются на базе Vue 3 Composition API и обеспечивают прозрачное взаимодействие с внутренними элементами библиотеки.


Создание простого Wrapper-компонента

Простейший пример Wrapper-компонента — обёртка над ElButton:

<template>
  <el-button :type="type" :size="size" @click="handleClick">
    <slot></slot>
  </el-button>
</template>

<script setup>
import { defineProps, defineEmits } from 'vue';
import { ElButton } from 'element-plus';

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

const emit = defineEmits(['click']);

function handleClick(event) {
  emit('click', event);
}
</script>

Ключевые моменты:

  • Props-передача: Wrapper должен передавать все необходимые свойства внутрь оригинального компонента (ElButton).
  • События: Использование defineEmits позволяет перехватывать события и при необходимости добавлять собственную логику.
  • Slot: Обеспечивает возможность вставки кастомного контента внутрь компонента.

Добавление логики и стилей

Wrapper-компоненты часто нужны для внедрения повторяемой логики или кастомных стилей. Например, добавим логику подтверждения перед выполнением действия кнопки:

<template>
  <el-button :type="type" :size="size" @click="confirmClick">
    <slot></slot>
  </el-button>
</template>

<script setup>
import { defineProps, defineEmits } from 'vue';
import { ElButton, ElMessageBox } from 'element-plus';

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

const emit = defineEmits(['click']);

async function confirmClick(event) {
  try {
    await ElMessageBox.confirm('Вы уверены?', 'Подтверждение');
    emit('click', event);
  } catch {
    // Отмена
  }
}
</script>

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

  • Используется встроенный ElMessageBox для подтверждения действия.
  • Wrapper перехватывает клик и добавляет бизнес-логику, не меняя интерфейс оригинального компонента.
  • Легко масштабируется для других кнопок с одинаковым поведением.

Унификация форм с Wrapper-компонентами

Wrapper-компоненты часто применяются для стандартизации форм. Например, создание единого FormInput:

<template>
  <el-form-item :label="label" :prop="prop">
    <el-input v-model="modelValue" :placeholder="placeholder" />
  </el-form-item>
</template>

<script setup>
import { defineProps, defineEmits } from 'vue';
import { ElFormItem, ElInput } from 'element-plus';

const props = defineProps({
  modelValue: String,
  label: String,
  prop: String,
  placeholder: String
});

const emit = defineEmits(['update:modelValue']);

function updateValue(value) {
  emit('update:modelValue', value);
}
</script>

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

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

Wrapper для сложных компонентов

Wrapper-компоненты полезны и для комплексных элементов, например, таблиц:

<template>
  <el-table :data="tableData" style="width: 100%">
    <el-table-column v-for="col in columns" :key="col.prop" :prop="col.prop" :label="col.label" />
    <slot name="actions"></slot>
  </el-table>
</template>

<script setup>
import { defineProps } from 'vue';
import { ElTable, ElTableColumn } from 'element-plus';

const props = defineProps({
  tableData: { type: Array, default: () => [] },
  columns: { type: Array, default: () => [] }
});
</script>

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

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

Использование provide/inject для взаимодействия Wrapper-компонентов

Для сложных интерфейсов удобно передавать данные между Wrapper-компонентами с помощью provide/inject:

// FormWrapper.vue
<template>
  <el-form :model="formData">
    <slot></slot>
  </el-form>
</template>

<script setup>
import { reactive, provide } from 'vue';
import { ElForm } from 'element-plus';

const formData = reactive({});
provide('formData', formData);
</script>

// FormInputWrapper.vue
<template>
  <el-form-item :label="label">
    <el-input v-model="formData[prop]" />
  </el-form-item>
</template>

<script setup>
import { inject, defineProps } from 'vue';
import { ElFormItem, ElInput } from 'element-plus';

const props = defineProps({ label: String, prop: String });
const formData = inject('formData');
</script>

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

  • Wrapper-компоненты становятся взаимосвязанными.
  • Возможность централизованной работы с состоянием формы.
  • Упрощение масштабируемости сложных интерфейсов.

Лучшие практики при создании Wrapper-компонентов

  1. Прозрачная передача props — все свойства должны передаваться внутрь базового компонента.
  2. Использование слотов — для сохранения гибкости контента.
  3. Минимизация логики внутри Wrapper — лучше выносить бизнес-логику в composables.
  4. Единый стиль и поведение — Wrapper-компоненты должны стандартизировать UI и UX.
  5. Документирование API Wrapper — важно четко описывать, какие props, слоты и события поддерживаются.

Wrapper-компоненты в Element Plus позволяют строить чистые, масштабируемые и повторно используемые интерфейсы, объединяя преимущества готовых компонентов и возможность внедрять кастомную логику без дублирования кода.