логотип PurpleSchool
логотип PurpleSchool

Создание и настройка кнопок в Vue приложениях

Автор

Олег Марков

Введение

Кнопки — один из самых частых UI-элементов в любых фронтенд-приложениях. Они управляют навигацией, вызывают действия, отправляют формы пользователя и просто делают интерфейсы интерактивнее. Vue — фреймворк, который позволяет не только создавать простые кнопки, но и строить мощные, переиспользуемые, удобно настраиваемые компоненты. Настраивать внешний вид, добавлять обработку событий, создавать кастомные или динамические варианты, объединять с библиотеками — всё это доступно даже новичкам.

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

Создание кнопки в Vue — первый шаг

Давайте начнём с самого простого: создание обычной кнопки и обработка событий нажатия.

Пример самой простой кнопки

<template>
  <button @click="handleClick">
    Нажми меня
  </button>
</template>

<script>
export default {
  name: 'SimpleButton',
  methods: {
    handleClick() {
      // Здесь опишите логику, которая выполнится при клике
      alert('Кнопка нажата!')
    }
  }
}
</script>

Здесь @click — это директива, которая реагирует на нажатие.

Объяснение:

  • <button> — стандартный HTML-элемент кнопки.
  • @click="handleClick" — привязывает обработчик события "click" (нажатие) к методу handleClick.
  • В методе handleClick можно реализовать любую нужную вам логику.

Теперь вы видите, как просто добавить интерактивную кнопку в проект на Vue.

Приём параметров (props) — кнопка со свойствами

Часто кнопки в приложениях имеют разные тексты, типы (primary, secondary), активны или нет. В Vue эти параметры удобно передавать через props.

Добавим динамический текст и disabled

<template>
  <!-- Кнопка получает текст и может быть заблокирована (disabled) -->
  <button :disabled="disabled" @click="handleClick">
    {{ label }}
  </button>
</template>

<script>
export default {
  name: 'CustomButton',
  props: {
    label: {
      type: String,
      required: true
    },
    disabled: {
      type: Boolean,
      default: false
    }
  },
  methods: {
    handleClick() {
      if (!this.disabled) {
        // Реализуем поведение только если кнопка активна
        this.$emit('clicked')
      }
    }
  }
}
</script>

В этом фрагменте:

  • label — динамическая надпись кнопки приходит как пропс.
  • Свойство disabled позволяет включать/выключать кнопку.
  • Вызывается пользовательский ивент clicked при нажатии (вместо alert).

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

<CustomButton label="Сохранить" :disabled="isSaving" @clicked="saveHandler"/>
  • Здесь видно, как происходит передача пропсов (надпись "Сохранить", кнопка становится disabled во время сохранения) и обработка клика с помощью своего обработчика (saveHandler).

Visual стилизация кнопок

Красивый внешний вид — важная часть. Давайте разберём варианты стилизации: через CSS, динамические классы и scoped-стили.

Стилизация с помощью CSS

<template>
  <button class="primary-btn">
    Красивая кнопка
  </button>
</template>

<style>
.primary-btn {
  background: #4caf50;
  color: #fff;
  padding: 10px 24px;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  font-size: 16px;
  margin: 8px;
}
.primary-btn:hover {
  background: #388e3c;
}
</style>

В этом примере:

  • Используется CSS-класс primary-btn.
  • При наведении (:hover) цвет фона меняется — реакция на действие пользователя.

Динамические классы и стили — кастомизация внешнего вида

Добавим props для типов кнопки.

<template>
  <button :class="buttonClass" @click="handleClick">
    {{ label }}
  </button>
</template>

<script>
export default {
  props: {
    label: String,
    type: {
      type: String,
      default: 'default'
    }
  },
  computed: {
    buttonClass() {
      // Определяем класс в зависимости от пропса type
      return {
        'btn': true,
        'btn-primary': this.type === 'primary',
        'btn-secondary': this.type === 'secondary',
        'btn-default': this.type === 'default'
      }
    }
  },
  methods: {
    handleClick() {
      this.$emit('clicked')
    }
  }
}
</script>

<style scoped>
.btn {
  font-weight: bold;
  padding: 10px 18px;
  border-radius: 4px;
  cursor: pointer;
  border: none;
  margin-right: 5px;
}
.btn-primary {
  background: #2196f3;
  color: #fff;
}
.btn-secondary {
  background: #e0e0e0;
  color: #38404a;
}
.btn-default {
  background: #fafafa;
  color: #222;
}
</style>

Здесь показан способ динамически менять классы и стили в зависимости от типа кнопки.

Иконки и слоты — расширяем компоненты кнопок

Иногда нужно добавить иконку или другой элемент внутрь кнопки. Для этого удобно использовать слоты — один из базовых механизмов Vue для расширения компонентов.

Пример кнопки с иконкой через слот

<template>
  <button class="with-icon-btn" @click="$emit('clicked')">
    <slot name="icon"></slot>
    <span>{{ label }}</span>
  </button>
</template>
  • Тут <slot name="icon"></slot> позволяет вставить SVG или любую разметку из родителя.

Использование в родителе:

<CustomButton label="Загрузить">
  <template #icon>
    <!-- Простая иконка загрузки SVG -->
    <svg width="16" height="16" viewBox="0 0 24 24"><path fill="#fff" d="..."/></svg>
  </template>
</CustomButton>

Так вы добавите любую иконку слева от текста и сможете повторно использовать компонент.

Обработка разных событий кнопки

Кнопки могут реагировать не только на click, но и на другие события: double click, mouseover, keypress и т. д.

Добавим несколько обработчиков

<template>
  <button
    @click="onClick"
    @dblclick="onDoubleClick"
    @mouseover="onMouseOver"
    :disabled="disabled"
  >
    {{ label }}
  </button>
</template>

<script>
export default {
  props: ['label', 'disabled'],
  methods: {
    onClick() {
      this.$emit('clicked')
    },
    onDoubleClick() {
      this.$emit('doubleClicked')
    },
    onMouseOver() {
      // Например, подсказка при наведении
      this.$emit('hovered')
    }
  }
}
</script>

В этом коде:

  • Есть три разных обработчика событий.
  • Каждый обработчик отправляет свой кастомный event наружу.

Это важно для продвинутых интерфейсов, где нужна разная реакция на разные действия пользователя.

Передача сложных параметров через события

Иногда важно не только обработать клик, но и передать контекст, объект, айдишник или другие данные.

Пример передачи параметров:

<template>
  <button @click="handleClick">
    {{ label }}
  </button>
</template>

<script>
export default {
  props: ['label', 'itemId'],
  methods: {
    handleClick() {
      // Передаем itemId наружу с событием 'clicked'
      this.$emit('clicked', this.itemId)
    }
  }
}
</script>

Использование:

<MyButton label="Удалить" :itemId="id" @clicked="removeItem"/>

В родительском компоненте:

methods: {
  removeItem(id) {
    // Теперь у вас есть id из кнопки
    // Можно удалить элемент с этим id
  }
}

Кастомизация HTML-атрибутов и accessibility

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

  • добавлять правильный тег (button, a, div)
  • устанавливать role, tabindex
  • указывать aria-атрибуты для доступности

Пример с дополнительными атрибутами

<template>
  <button
    :aria-label="ariaLabel"
    :aria-pressed="ariaPressed"
    :tabindex="tabIndex"
    @click="handleClick"
  >
    {{ label }}
  </button>
</template>

<script>
export default {
  props: {
    label: String,
    ariaLabel: String,
    ariaPressed: Boolean,
    tabIndex: {
      type: Number,
      default: 0
    }
  },
  methods: {
    handleClick() {
      this.$emit('clicked')
    }
  }
}
</script>

Эти атрибуты помогут сделать ваше приложение удобным не только для мыши, но и для клавиатуры и экранных читалок.

Use-case: повторно используемый компонент кнопки

Главное преимущество Vue — возможность создать универсальный компонент "Кнопка", который вы будете использовать во всём проекте, меняя только пропсы. Давайте реализуем расширяемый и гибкий компонент.

Универсальный компонент кнопки с типами, иконками и кастомными событиями

<template>
  <button
    :class="buttonClass"
    :disabled="disabled"
    :aria-label="ariaLabel"
    @click="handleClick"
  >
    <slot name="icon"/>
    <span v-if="label">{{ label }}</span>
    <slot/>
  </button>
</template>

<script>
export default {
  name: 'AppButton',
  props: {
    label: String,
    type: String, // primary, secondary, danger и т. д.
    disabled: Boolean,
    ariaLabel: String
  },
  computed: {
    buttonClass() {
      // Можно использовать Map классов как раньше
      return [
        'app-btn',
        this.type ? `app-btn--${this.type}` : 'app-btn--default'
      ]
    }
  },
  methods: {
    handleClick(event) {
      if (!this.disabled) {
        this.$emit('clicked', event)
      }
    }
  }
}
</script>

<style scoped>
.app-btn {
  border: none;
  padding: 10px 20px;
  border-radius: 6px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  transition: background 0.2s;
  font-size: 16px;
}
.app-btn--primary { background: #1976d2; color: #fff; }
.app-btn--secondary { background: #fff; color: #1976d2; border: 1px solid #1976d2; }
.app-btn--danger { background: #d32f2f; color: #fff; }
.app-btn--default { background: #eee; color: #333; }
.app-btn:disabled { cursor: not-allowed; opacity: 0.7; }
.app-btn svg { margin-right: 0.5em; }
</style>

Теперь у вас гибкий компонент:

  • Можно задавать тип (primary, danger...)
  • Передавать любой контент через слоты (текст, иконки)
  • Управлять доступностью и событиями

Использование:

<AppButton label="Добавить" type="primary" @clicked="addItem">
  <template #icon>
    <span class="material-icons">add</span>
  </template>
</AppButton>

Такой компонент закрывает 95% задач с кнопками.

Подключение к сторонним UI-библиотекам (Vuetify, Element, BootstrapVue)

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

Как использовать кнопки из UI-библиотеки (на примере Vuetify):

<template>
  <v-btn color="primary" :disabled="loading" @click="save">
    Сохранить
  </v-btn>
</template>
  • Здесь <v-btn> — уже готовый компонент c десятками параметров.
  • Можно спокойно применять любые параметры: цвет, иконки, отключение, размеры, ripple-эффекты и многое другое.

Но если вам нужна максимальная кастомизация — создавать свои компоненты всё равно полезно.

Лучшие практики работы с кнопками в Vue

  • Используйте стандартный тег <button> как можно чаще, это помогает доступности.
  • Всегда используйте пропс disabled вместо управления стилем (user-select: none) для блокировки.
  • Для повторного использования создавайте отдельный компонент кнопки.
  • Делайте внешний вид кнопки управляемым через props, классы, стили и слоты.
  • Не забывайте про accessibility: aria-атрибуты, правильные роли, поддержка клавиатуры.
  • Если ваша кнопка что-то отправляет — работайте через события, не связывайте логику жёстко внутри компонента.
  • Для сложных кейсов объединяйте кнопку с другими компонентами (например, лоадеры, popover, иконки).

Заключение

На практике работа с кнопками в Vue начинается с простых сценариев, но быстро может дойти до сложных, универсальных и интерактивных компонентов с поддержкой accessibility. Используйте props для параметризации, слоты для расширения и событийную модель для интеграции с логикой приложения. Совершенствуйте свой универсальный компонент кнопки, чтобы ускорить разработку и достичь единообразия в продукте.


Частозадаваемые технические вопросы и ответы

Как добавить состояние загрузки (loading) в кнопку?

Добавьте отдельный prop loading и отобразите индикатор загрузки (например, спиннер). Отключите кнопку при загрузке: vue <button :disabled="loading" @click="clickHandler"> <span v-if="loading">Загрузка...</span> <span v-else>{{ label }}</span> </button>

Как передавать ref/ссылку на кнопку во Vue 3?

Можно использовать ref и defineExpose: vue <template> <button ref="myButtonRef"> Кнопка </button> </template> <script setup> import { ref } from 'vue' const myButtonRef = ref(null) defineExpose({ myButtonRef }) </script> Теперь родитель может получить ссылку на DOM-элемент кнопки.

Как сделать кнопку с выпадающим меню (dropdown)?

Лучше создать отдельный компонент, где кнопка показывает/скрывает выпадающее меню через реактивную переменную (например, isOpen). Используйте v-if/v-show и контролируйте видимость по клику.

Как зафиксировать кнопку внизу экрана?

Обеспечьте нужное позиционирование через CSS: css .fixed-bottom-btn { position: fixed; bottom: 32px; right: 20px; z-index: 1000; } Передайте этот класс через props или словарь классов.

Почему у моей кнопки иногда не срабатывает событие click?

Возможно, кнопка заблокирована (disabled) или перекрыта другими элементами (z-index/overflow). Проверьте слои и убедитесь, что событийный обработчик именно на кнопке и активен.


Стрелочка влевоСоздание и настройка кнопок в VueРабота с lifecycle-хуками beforeCreate и beforeMount во VueСтрелочка вправо

Все гайды по Vue

Руководство по валидации форм во Vue.jsИнтеграция Tiptap для создания редакторов на VueРабота с таблицами во Vue через TanStackИнструкция по установке и компонентам Vue sliderУправление пакетами Vue js с помощью npmУправление пакетами и node modules в Vue проектахКак использовать meta для улучшения SEO на VueПолный гайд по компоненту messages во Vuejs5 правил использования Inertia с Vue и LaravelРабота с модулями и пакетами в VueИнструкция по работе с grid на VueGithub для Vue проектов - подробная инструкция по хранению и совместной работеНастройка ESLint для Vue проектов и поддержка качества кодаОбработка ошибок и отладка в Vue.jsИспользование Vue Devtools для отладки и мониторинга приложенийРабота с конфигурационными файлами и скриптами VueСоздание и настройка проектов Vue с помощью Vue CLI3 способа интеграции Chart.js с Vue для создания графиковРабота с Canvas во VueИнструкция по реализации календаря во VueРабота с Ant Design Vue для создания UI на Vue
Обзор и использование утилит Vue для удобной разработкиРабота с обновлениями компонента и жизненным циклом updateРазрешение конфликтов и ошибок с помощью Vue resolveИспользование query-параметров и их обработка в маршрутах VueЗагрузка и управление состоянием загрузки в VueИспользование библиотек Vue для расширения функционалаРабота с JSON данными в приложениях VueКак работать с экземплярами компонента Instance во VueПолучение данных и API-запросы во Vue.jsЭкспорт и импорт данных и компонентов в VueОбработка событий и их передача между компонентами VuejsГайд по defineEmits на Vue 3Понимание core функционала Vue и его применениеПонимание и применение Composition API в Vue 3Понимание и работа с компилятором VueКогда и как использовать $emit и call во VueВзаимодействие с внешними API через Axios в Vue
Веб приложения на Vue архитектура и лучшие практикиИспользование Vite для быстрого старта и сборки проектов на Vue 3Работа с URL и ссылками в приложениях на VueРабота с пользовательскими интерфейсами и UI библиотеками во VueОрганизация и структура исходных файлов в проектах VueИспользование Quasar Framework для разработки на Vue с готовыми UI-компонентамиОбзор популярных шаблонов и стартовых проектов на VueИнтеграция Vue с PHP для создания динамичных веб-приложенийКак организовать страницы и маршруты в проекте на VueNuxt JS и Vue 3 для SSR приложенийСоздание серверных приложений на Vue с помощью Nuxt jsИспользование Vue Native для разработки мобильных приложенийОрганизация и управление индексной страницей в проектах VueИспользование Docker для контейнеризации приложений на VueИнтеграция Vue.js с Django для создания полноценных веб-приложенийСоздание и работа с дистрибутивом build dist Vue приложенийРабота со стилями и CSS в Vue js для красивых интерфейсовСоздание и структурирование Vue.js приложенияКак исправить ошибку cannot find module vueНастройка и сборка проектов Vue с использованием современных инструментовИнтеграция Vue с Bitrix для корпоративных решенийРазработка административных панелей на Vue js
5 библиотек для создания tree view во VueИнтеграция Tailwind CSS с Vue для современных интерфейсовИнтеграция Vue с серверной частью и HTTPS настройкамиКак обрабатывать async операции с Promise во VueИнтеграция Node.js и Vue.js для разработки приложенийРуководство по интеграции Vue js в NET проектыПримеры использования JSX во VueГайд по импорту и регистрации компонентов на VueМногоязычные приложения на Vue с i18nИнтеграция FLIR данных с Vue5 примеров использования filter во Vue для упрощения разработки3 примера реализации drag-and-drop во Vue
Управление переменными и реактивными свойствами во VueИспользование v for и slot в VueПрименение v-bind для динамической привязки атрибутов в VueУправление пользователями и их данными в Vue приложенияхСоздание и использование UI Kit для Vue приложенийТипизация и использование TypeScript в VuejsИспользование шаблонов в Vue js для построения интерфейсовИспользование Swiper для создания слайдеров в VueРабота со стилями и стилизацией в VueСтруктура и особенности Single File Components SFC в VueРабота со SCSS в проектах на Vue для стилизацииРабота со скроллингом и прокруткой в Vue приложенияхПрименение script setup синтаксиса в Vue 3 для упрощения компонентовИспользование scoped стилей для изоляции CSS в компонентах Vue3 способа улучшить навигацию Vue с push()Обработка запросов и асинхронных операций в VueПонимание и использование provide inject для передачи данных между компонентамиПередача и использование props в Vue 3 для взаимодействия компонентовПередача данных между компонентами с помощью props в Vue jsУправление property и функциями во Vue.jsРабота со свойствами компонентов VueУправление параметрами и динамическими данными во VueРабота с lifecycle-хуком onMounted во VueОсновы работы с объектами в VueПонимание жизненного цикла компонента Vue js на примере mountedИспользование модальных окон modal в Vue приложенияхИспользование методов в компонентах Vue для обработки логикиИспользование метода map в Vue для обработки массивовИспользование хуков жизненного цикла Vue для управления состоянием компонентаРабота с ключами key в списках и компонентах VueОбработка пользовательского ввода в Vue.jsРабота с изображениями и их оптимизация в VueИспользование хуков жизненного цикла в VueОрганизация сеток и гридов для верстки интерфейсов на VueСоздание и управление формами в VueОрганизация файлов и структура проекта Vue.jsКомпоненты Vue создание передача данных события и emitРабота с динамическими компонентами и данными в Vue3 способа манипулирования DOM на VueРуководство по div во VueИспользование директив в Vue и их расширенные возможностиОсновы и применение директив в VueИспользование директив и их особенности на Vue с помощью defineИспользование компонентов datepicker в Vue для выбора датОрганизация циклов и итераций во VueКак работает компиляция Vue CoreСоздание и использование компонентов в Vue JSОбработка кликов и пользовательских событий в VueИспользование классов в Vue для организации кода и компонентовИспользование директивы checked для управления состоянием чекбоксов в VueГайд на checkbox компонент во VueОтображение данных в виде графиков с помощью Vue ChartСоздание и настройка кнопок в VueСоздание и настройка кнопок в Vue приложенияхРабота с lifecycle-хуками beforeCreate и beforeMount во VueИспользование массивов и методов их обработки в VueИспользование массивов и их обработка в Vue
Использование Vuetify для создания современных интерфейсов на VueИспользование transition во VueТестирование компонентов и приложений на VueРабота с teleport для управления DOM во VueПять шагов по настройке SSR в VuejsИспользование Shadcn UI компонентов с Vue для продвинутых интерфейсовИспользование router-link для навигации в Vue RouterКак использовать require в Vue для динамического импорта модулейРабота с динамическим рендерингом и виртуальным DOM на Vue.jsИспользование ref для управления ссылками и реактивностью в Vue 3Использование Vue Pro и его преимущества для профессиональной разработкиРуководство по nextTick для работы с DOMСоздание и использование компонентов с помощью Vue js и CУправление состоянием и реактивностью через inject и provideДинамическое обновление компонентов и данных на VueГлубокое изучение документации Vue и как эффективно её использоватьИспользование Crystal с Vue для разработкиИспользование вычисляемых свойств для динамического отображения данных на Vue jsОптимизация производительности и предупреждения в Vue
Открыть базу знаний