strokoff

Разрабатываем переиспользуемые Vue.js компоненты

В этой статье мы рассмотрим основные подходы при создании переиспользуемого компонента на примере кнопки.

Зачем мне это?

Ведь уже существует нативная реализация элемента button, зачем мне еще один компонент кнопки? С помощью компонента мы сможем сделать

Предисловие

Данная статья написана для тех, у кого уже есть базовое понимание Vue.js и javascipt’a. Главный фокус в статье основан на javascript и как он взаимодействует с DOM. Автор не дает гарантий, что приведенные практики будут работать в будущих версиях Vue.js, также автор не дает гарантии, что его личные практики, являются лучшими практиками.

Boilerplate

Автор подготовил github репозиторий в который вы можете склонировать и получить базовый проект для дальнейшей работы. После клонирования и установки репозитория локально, вы можете установить все зависимости одной командой npm install после установки всех зависимостей мы можем запустить из корневой директории наш проект npm run dev. После выполнения запустится наш dev сервер и будет доступен по адресу localhost:8080.

Tutorial

Давайте уже наконец-то откроем src/components/Button/Button.vue и внесем следующие изменения

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

Структура приложения

По умолчанию для импорта компонента вы должны указать относительный путь от текущего компонента, в маленьких приложениях это небольшая задача, но в больших это становится весьма трудоемкой задачей, чтобы упростить себе жизнь, автор использует возможности webpack и создает alias для директории src/components это позволит избежать прописывания относительных путей по проекту. Импорт компонентов будет выглядеть следующим образом:

Настройка alias в webpack.config.js выглядит так:

Возможно, вам интересно, почему я даю каждому компоненту свой собственный каталог. Я делаю это, чтобы предоставить мне место для хранения файлов, связанных с компонентом. Это могут быть изображения, используемые в компоненте или дочерние компоненты, которые будут использоваться только конкретным компонентом. (Например, компонент слайдера имеет компоненты слайдов).

Содержимое кнопки

Компонент Button должен быть добавлен к нашему приложению. Откройте приложение App.vue и импортируйте его так:

Компонент по-прежнему должен быть локально зарегистрирован, прежде чем его можно будет использовать. Измените components для компонента App, чтобы включить компонент Button:

Мы присваиваем компоненту Button имя тега v-button, чтобы избежать конфликтов с нативным Button HTML элементом

В итоге мы добавляем наш компонент в наш template

Для управления содержимым кнопки, мы будем пользоваться возможностями slot. Подробнее об использовании slot вы можете прочитать здесь. Вы не ограничены передачей только строки в слот, к примеру можно передать template, иконку или вовсе другой компонент.

Добавляем интерактивности через props

Хорошо, до сих пор наш компонент Button довольно скучный. На данный момент это не что иное, как раздутая реализация собственной HTML-кнопки. Чтобы сделать компонент Button полезным, нам нужно добавить опцию для передачи события click из родительского компонента. Это делается с помощью реквизита.

Откройте Button.vue, пока мы только изменили шаблон. Чтобы позволить нашему родительскому компоненту отправить метод нашему компоненту Button, нам нужно определить onClick prop:

В вышесказанном мы описываем компоненту Button свойство onClick. Данное свойство является функцией и оно обязательно для компонента (использование кнопки без реагирования на клик, бесполезно).

Подписываем click event в DOM

Наш компонент по прежнему не реагирует на клик, чтобы исправить это, мы воспользуемся директивой v-on чтобы подписать метод onClick переданный в prop. Мы будем использовать краткую запись @click, что равносильно написанию v-bind:click

Если попытаться нажать кнопку сейчас, то ничего не произойдет т.к. мы не передали значение в onClick prop.

Передаем метод из родительского в дочерний компонент

Откройте App компонент из src/App.vue и создайте метод consoleClick который будет логировать в консоль наше событие.

Теперь мы готовы передать метод из нашего App в наш Button компонент

Теперь при клике на кнопку, вы можете увидеть запись в консоли браузера. Таким образом мы передали метод из родительского компонента в дочерний (при этом еще сделали валидацию на функцию), в целом вы можете передавать любой тип данных в props.

Использование нескольких инстансов компонентов

Компоненты небыли бы такими прикольными, если бы их нельзя было использовать повторно. Давайте добавим еще один метод в наш App, назовем его alertClick.


Теперь просто добавим еще один компонент Button в нашем шаблоне и укажем метод alertClick

Теперь у нас есть две кнопки, одна логирует, вторая выводит алерт. Все просто.

Свободная функциональность

Поскольку мы использовали нативный элемент кнопки в качестве корневого элемента нашего компонента Button, мы получили некоторую свободную функциональность. Если бы мы использовали div как корневой элемент, мы бы не смогли использовать нативные возможности элемента Button. Плюсом также остается семантическая корректность нашей верстки. Давайте для примера добавим свойство disabled одной из наших кнопок.

Заключение

Теперь у нас есть свой кастомный компонент кнопки, который мы можем расширять своей логикой. Следите за обновлениями в будушем.

Данная статья является вольным переводом этого урока.