Пользовательские компоненты на базе Element Plus

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


Импорт и регистрация компонентов

Для начала необходимо импортировать нужные элементы из библиотеки и зарегистрировать их в компоненте или глобально:

import { ElButton, ElInput } from 'element-plus';
import 'element-plus/dist/index.css';

export default {
  components: {
    ElButton,
    ElInput,
  },
};

Ключевой момент: локальная регистрация позволяет изолировать компоненты и уменьшает объем глобального контекста, что особенно важно для крупных проектов.


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

Часто возникает необходимость создать собственный компонент, расширяющий функциональность базового элемента Element Plus. Например, кнопка с дополнительной анимацией и кастомным стилем:

<template>
  <el-button
    :type="type"
    :disabled="disabled"
    @click="handleClick"
    class="custom-button"
  >
    <slot></slot>
  </el-button>
</template>

<script>
export default {
  name: 'CustomButton',
  props: {
    type: {
      type: String,
      default: 'primary',
    },
    disabled: {
      type: Boolean,
      default: false,
    },
  },
  methods: {
    handleClick(event) {
      this.$emit('click', event);
      console.log('CustomButton clicked');
    },
  },
};
</script>

<style scoped>
.custom-button {
  transition: transform 0.2s ease;
}
.custom-button:hover {
  transform: scale(1.05);
}
</style>

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

  • Использование slot позволяет вставлять любой контент внутрь кнопки.
  • Прокидывание событий через $emit сохраняет привычный интерфейс взаимодействия.
  • Scoped CSS гарантирует, что стили не затронут другие кнопки.

Использование слотов для расширенной кастомизации

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

<template>
  <el-input v-model="inputValue" placeholder="Введите текст">
    <template #prefix>
      <i class="el-icon-search"></i>
    </template>
    <template #suffix>
      <el-button size="mini" @click="clearInput">Очистить</el-button>
    </template>
  </el-input>
</template>

<script>
import { ref } from 'vue';
export default {
  setup() {
    const inputValue = ref('');
    const clearInput = () => {
      inputValue.value = '';
    };
    return { inputValue, clearInput };
  },
};
</script>

Примечание: именованные слоты (#prefix, #suffix) дают возможность полностью контролировать элементы интерфейса внутри стандартного компонента.


Создание глобального пользовательского компонента

Чтобы компонент был доступен во всем приложении, его регистрируют глобально:

import { createApp } from 'vue';
import App from './App.vue';
import CustomButton from './components/CustomButton.vue';
import ElementPlus from 'element-plus';
import 'element-plus/dist/index.css';

const app = createApp(App);
app.use(ElementPlus);
app.component('CustomButton', CustomButton);
app.mount('#app');

Преимущество: позволяет использовать компонент в любом месте приложения без повторного импорта.


Интеграция с реактивными данными и формами

Element Plus предоставляет мощные компоненты для работы с формами (ElForm, ElFormItem, ElInput). Пользовательский компонент может быть полностью совместим с валидацией:

<template>
  <el-form :model="formData" :rules="rules" ref="formRef">
    <el-form-item label="Имя" prop="name">
      <custom-input v-model="formData.name"></custom-input>
    </el-form-item>
    <el-form-item>
      <el-button type="primary" @click="submitForm">Отправить</el-button>
    </el-form-item>
  </el-form>
</template>

<script>
import { ref } from 'vue';
import CustomInput from './CustomInput.vue';

export default {
  components: { CustomInput },
  setup() {
    const formData = ref({ name: '' });
    const rules = {
      name: [{ required: true, message: 'Введите имя', trigger: 'blur' }],
    };
    const formRef = ref(null);
    const submitForm = () => {
      formRef.value.validate(valid => {
        if (valid) {
          console.log('Форма корректна', formData.value);
        } else {
          console.log('Ошибка валидации');
        }
      });
    };
    return { formData, rules, formRef, submitForm };
  },
};
</script>

Особенности: пользовательский компонент CustomInput полностью поддерживает v-model и валидацию форм Element Plus.


Расширение глобальных тем и стилей

Для масштабных проектов важна единая стилизация. Element Plus поддерживает CSS переменные и SCSS. Пользовательские компоненты могут использовать переменные темы:

.custom-button {
  background-color: var(--el-color-primary);
  color: var(--el-color-white);
  &:hover {
    background-color: var(--el-color-primary-dark-2);
  }
}

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


Комбинация нескольких компонентов в сложные виджеты

Элементарные компоненты Element Plus можно объединять в более сложные пользовательские виджеты. Пример: компонент карточки с кнопкой действия и статусом:

<template>
  <el-card class="custom-card">
    <div class="header">{{ title }}</div>
    <div class="body">{{ content }}</div>
    <div class="footer">
      <el-button type="success" @click="onConfirm">Подтвердить</el-button>
    </div>
  </el-card>
</template>

<script>
export default {
  props: ['title', 'content'],
  methods: {
    onConfirm() {
      this.$emit('confirm');
    },
  },
};
</script>

<style scoped>
.custom-card {
  width: 300px;
  margin: 16px;
}
.header {
  font-weight: bold;
  margin-bottom: 8px;
}
.body {
  margin-bottom: 12px;
}
</style>

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


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