Миксины в Vue.JS занимают немного серую зону функциональности от среднего до продвинутого уровня. Немного похожи на компоненты, отделены от итераций самих себя, полезны для поддержки СУХОГО (не повторяйте себя) кода; но недостаточно доступного различия вариантов использования от управления состоянием или даже просто правильных фильтров, и с достаточным количеством подводных камней, чтобы многие разработчики дважды подумали об их использовании.

Обратите внимание, что здесь я имею в виду примеси конкретно в Vue/React примеси, примеси для синтаксиса классов ES6 и т. д., которые представляют собой совсем другое животное.

Чтобы пролить свет на полезность и ограничения миксинов Vue, мы собираемся собрать небольшую демонстрацию. Я надеюсь, что эта демонстрация нарисует достаточно ясную картину с достаточно четкими демаркационными линиями, подразумевающими, когда вы должны (или можете) или не должны прибегать к миксину Vue, а также предоставит некоторую практику быстрого выхода из ворот с помощью рабочий процесс проекта vue-cli.

Без дальнейших церемоний,

Для этого проекта вам понадобится следующее:

  • NodeJS — обязательно скачайте версию с пометкой Рекомендуется для большинства пользователей.
  • npm — менеджер пакетов узла будет установлен вместе с установкой NodeJS выше; не стесняйтесь использовать альтернативный менеджер пакетов, если вы так склонны

И мы будем использовать (после того, как установим их с помощью npm):

  • VueJS — мы будем использовать ряд специфичных для vue методов и синтаксиса, которые я постараюсь прояснить по мере продвижения (хотя это не урок по Vue, как таковой); если вы не знакомы с Vue, я настоятельно рекомендую вам ознакомиться с их отличной документацией.
  • Vue-cli — интерфейс командной строки Vue, который позволит нам быстро собрать шаблонный проект Vue.

И это все!

Для начала скачайте и установите NodeJS по ссылке выше. Затем откройте любимое окно терминала и перейдите в каталог, где вы хотите создать папку проекта.

Используйте следующую команду для установки vue-cli:

npm install -g @vue/cli

npm объявляет команду менеджера пакетов узла, install — контекстно-зависимая команда, которую мы запускаем, -g — модификатор, который заставит наш install как глобальный (для всей машины, а не для текущего каталога), а @vue-cli — это устанавливаемый пакет.

Это позволит вам запускать команды, начинающиеся с vue. Теперь, чтобы создать папку нашего проекта, в том же окне терминала введите:

vue create vue-mixins-demo

При этом выполняется команда vue, create, которая создаст шаблонную папку проекта для проекта под названием «vue-mixins-demo». Просто нажмите «Ввод», чтобы выбрать все значения по умолчанию, когда вам будет предложено задать один или два вопроса в процессе создания. Теперь вы сможете увидеть папку проекта «vue-mixins-demo» в текущем каталоге и сможете открыть ее в текстовом редакторе или IDE по вашему выбору.

Все еще в том же окне терминала (не паникуйте, если вы его закрыли, просто откройте новое и снова перейдите в тот же каталог, содержащий папку вашего проекта), мы переходим в папку нашего проекта с помощью:

cd vue-mixins-demo

и следуйте этой команде:

npm run serve

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

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

Теперь мы все готовы начать писать код.

То, что мы собираемся создать, — это небольшое веб-приложение, показывающее полностью сортируемый список всех пользователей, а также список активных пользователей и список неактивных пользователей (конечно, используя фиктивные данные). Рассматриваемые данные пользователя:

Все данные были сгенерированы случайным образом из Random User API (подробнее об этом и замене статических данных данными, полученными из API, ближе к концу).

Для начала удалите компонент HelloWorld из стандартного кода и удалите все ссылки на него из файла App.vue. Фактически, замените все содержимое вашего файла App.vue следующим:

Как видите, мы будем отображать три новых компонента в представлении приложения. Теперь давайте создадим файлы для всех наших компонентов, чтобы наше приложение не вылетало, пока мы вносим изменения. Создайте файлы AllUsers.vue, Active.vue, Inactive.vue и User.vue в папке компонентов вашего проекта.

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

Код компонента User будет следующим:

В настоящее время для удобства я включил стили (это не урок CSS). Однако обратите внимание на свойство «реквизит» в блоке сценария. Это настройка этого пользовательского компонента для получения некоторого свойства данных, называемого «пользователь», от его родителя при его рендеринге. Поскольку мы уже знаем, как будет выглядеть «пользовательский» объект, мы можем безопасно экстраполировать, какую информацию мы будем извлекать из этого объекта и как.

Именно об этом сообщает привязка данных в разметке шаблона (user.name, user.status и т. д.). Обратите внимание, что v-bind — это единственная директива vue, отображаемая здесь на данный момент.

В случае элемента div в строке 7 его атрибут класса был связан таким образом, что элемент div получит класс «активный» или «неактивный» в зависимости от значения свойства «статус» его «пользователя». » объект (если статус равен 1, пользователь активен, если статус равен 0, пользователь неактивен).

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

Компонент AllUsers

Теперь давайте настроим его родительский компонент AllUsers:

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

Помимо содержащего div и h2, все, что у нас есть, это неупорядоченный список, содержащий один шаблон нашего пользовательского компонента (который, помните, будет отображать элемент списка с информацией об одном пользователе), на котором мы использовали v- для директивы дублировать этот компонент столько раз, сколько существует объекта «пользователь» в нашем массиве «пользователи» в данных этого компонента. Таким образом, у нас должно получиться 12 пользовательских компонентов, по одному для каждого пользователя.

Обратите внимание на строку 8, в которой атрибут «пользователь» привязан к значению «пользователь». Это может сбивать с толку, если вы не знакомы с привязкой данных Vue. Знак «:» указывает на директиву v-bind, а «пользователь», следующий сразу после имени атрибута, служит именем свойства данных, которое передается в этот компонент. «Пользователь» на противоположной стороне знака равенства — это отдельный пользовательский объект, извлеченный из массива «пользователи». Таким образом, мы передаем один отдельный пользовательский объект в качестве свойства «user» в каждый пользовательский компонент (гм). Именно так компонент User понимает, из какого объекта нужно получить имя пользователя, возраст, статус и созданную информацию.

Сортировка пользователей

Теперь у вас должно быть функциональное приложение, показывающее что-то вроде этого:

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

Мы добавили интерактивные переключатели, значения которых привязаны к свойствам, общим для наших пользовательских объектов (имя, возраст, статус, создано, изображение). Вычисляемое свойство userProperties извлекает все свойства из пользовательского объекта, а цикл v-for отображает столько переключателей и меток, сколько userProperties извлекает свойства (с одним v-if, чтобы убедиться, что мы не отображаем переключатель с надписью « изображение», так как было бы бессмысленно пытаться сортировать пользователей по URL-адресу их изображения). Значения наших переключателей также привязаны к новому ключу данных sortCriteria. Если пользователь нажимает переключатель «возраст», значение sortCriteria будет установлено на «возраст» и т. д.

Мы также добавили базовый метод sort_by, который сортирует массив по заданным свойствам (например, в алфавитном порядке по имени или в числовом порядке по дате).

Затем есть свойство компьютера sortedUsers, которое возвращает массив наших пользователей, отсортированных в соответствии с новой точкой данных sortCriteria (которая остается пустой, если ни один переключатель не отмечен), путем вызова метода sort_by и подачи пользователей и данных sortCriteria в качестве аргументов. .

Самое главное, мы обновили цикл v-for, который отображает наши компоненты User так, чтобы они извлекались из данных sortedUsers, а не из исходного массива пользователей. Таким образом, порядок пользовательских компонентов, отображаемых на странице, будет реагировать на любые изменения в свойстве sortedUsers, которое будет реактивно изменяться всякий раз, когда какие-либо из отслеживаемых данных претерпевают какие-либо изменения (например, sortCriteria, когда пользователь щелкает переключатель ).

И вот так у нас есть сортируемый список пользователей, который должен выглядеть примерно так:

Активные и неактивные компоненты

Теперь давайте создадим два новых компонента, Active.vue и Inactive.vue, которые будут отображать списки активных и неактивных пользователей (пользователи со статусом 1 будут считаться активными, а пользователи со статусом 0 будут считаться неактивными).

Однако, поскольку мы хотим, чтобы активные и неактивные списки пользователей были несколько усечены, мы не будем отображать компоненты User внутри этих списков. Они будут более информативными по сравнению с более полным списком AllUsers.

Эти компоненты будут выглядеть следующим образом:

В дополнение к переносу в этот компонент тех же данных о пользователях, методе sort_by и свойстве компьютера sortedUsers мы создали новый ключ данных под названием «status», который будет использоваться для указания того, активны или нет пользователи, которые будут представлены в этом компоненте. inactive, и мы создали новый метод filter_active_inactive, который использует ключ «status» в качестве механизма фильтрации для отбраковки массива пользователей ТОЛЬКО до активных пользователей, и мы используем отфильтрованный массив возвращенных пользователей в качестве аргумента в методе sort_by в свойство sortedUsers этого компонента.

Вы можете полностью продублировать этот компонент, переключив свойство статуса на 0 и заголовок с «Активные пользователи» на «Неактивные пользователи», чтобы безопасно получить как активные, так и неактивные компоненты.

Итак, здесь есть кое-что новое; в то же время, по сравнению с AllUsers.vue, там МНОГО старого. Много повторяющегося кода и даже повторяющихся функций. Здесь наконец проявляется преимущество примесей.

Наконец-то миксин

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

В папке «src» вашего проекта создайте новую папку с именем «mixins», а внутри этой папки создайте файл с именем «filterUsers.js». В этом файле мы просто соберем весь избыточный код, который повторяется между нашими компонентами AllUsers, Active и Inactive:

(опять же, не забудьте заменить сокращенные фиктивные данные о пользователях полным массивом пользователей из приведенного выше)

Мы объединили весь избыточный код в одну константу, которую экспортируем. Мы можем импортировать это в файлы наших компонентов и объединить все эти данные с данными наших компонентов без каких-либо конфликтов.

Теперь давайте высушим код других наших компонентов:

Как видите, все повторяющиеся пользовательские данные, повторяющиеся методы и свойства компьютера были полностью удалены (я даже переместил свойство компьютера userProperties в файл примеси, хотя оно использовалось только одним компонентом; функционально это просто сделало смысл для меня).

Затем мы импортируем { filterUsers } в каждый компонент, который требует содержащихся в нем функций (AllUsers, Active и Inactive), и просто объявляем его внутри объекта Vue, экспортируемого нашими компонентами, с помощью строки 23 или строки 35 в файлах выше, соответственно (примечание , свойство «mixins» компонента Vue всегда будет содержать массив!).

Наши методы и вычисляемые свойства в файле примеси содержат операторы if, которые гарантируют, что приложение не выдаст ошибку, если определенная часть головоломки отсутствует на стороне компонента (AllUsers не содержит свойство состояния, а Active и Inactive не содержат). содержат свойство sortCriteria, см. строки 20 и 39 в файле filterUsers.js. Таким образом, мы сделали наш код миксина намного более устойчивым к неожиданным ошибкам и намного более адаптируемым для использования в различных случаях использования компонентов.

Все три компонента, которые используют этот миксин, отображают контент на основе одних и тех же пользовательских данных, и все три имеют доступ к одним и тем же методам и вычисляемым свойствам, которые в противном случае повторялись бы во всем нашем приложении и сильно загромождали бы сами файлы компонентов. И наше приложение продолжает работать, как и ожидалось, без сбоев!

Полный код смотрите здесь.

Подводные камни

Как я уже упоминал, есть несколько подводных камней, о которых следует помнить при работе с миксинами Vue.

Первый и самый доступный заключается в том, что при использовании миксинов в ваших компонентах последнее слово всегда будет за вашими компонентами. Я имею в виду, что собственная внутренняя архитектура вашего компонента будет загружаться ПОСЛЕ содержимого миксина, что означает, что ваш компонент будет оборудован для перезаписи любых данных, методов, свойств или иного содержимого внутри файла миксина. Это имеет смысл практически с любой точки зрения, но я не хочу, чтобы кто-то совершил ошибку, думая, что включение миксина для перезаписи данных компонента в таком-то случае использования сработает. Этого не будет.

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

Конечно, это не проблема сама по себе, но, безусловно, что-то важное для понимания.

Чтобы выразить это более четко с точки зрения приложения, которое мы только что создали, предположим, что вы хотите создать функцию для изменения статуса пользователя с активного на неактивный в списке AllUsers. Это было бы достаточно легко сделать с помощью метода, который вы могли бы включить либо в компонент AllUsers, либо в миксин filterUsers. Этот метод предположительно изменит статус данного пользователя внутри массива пользователей в данных, что приведет к обновлению вычисляемого свойства sortedUsers для отражения новых данных. Однако эти обновленные данные будут отражаться только внутри компонента, из которого был выполнен метод. Мы увидели бы изменение статуса пользователя только внутри компонента AllUsers. Мы неувидели бы, как пользователь переходит из списка неактивных в список активных, как можно было бы ожидать.

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

Это очень важно. Чтобы отразить изменение в другом месте, некоторые даже должны быть испущены или какое-то состояние должно быть изменено.

Это еще более важно при рассмотрении возможности извлечения этих пользовательских данных из API, а не их жесткого кодирования. Это вполне жизнеспособный (и даже рекомендуемый) подход, но я должен напомнить вам, что эти пользовательские данные были получены из Random User API. Если бы мы выполнили выборку к Random User API, чтобы получить двенадцать пользователей, где бы ни выполнялся код этого миксина, это составило бы три разных вызова API.

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

На самом деле вы обычно не полагаетесь на рандомизированные пользовательские данные, так что это не обязательно проблема; но вы все равно будете выполнять три вызова API, чтобы получить одну и ту же идентичную информацию.

Однако решить эту проблему достаточно просто. Полностью удалите пользователей из миксина и сверните их (или один вызов API для их извлечения) в родительское представление, App.vue, и просто передайте их трем дочерним компонентам в качестве реквизита. Перенастройте радиокнопки в AllUsers.vue, чтобы генерировать событие, которое прослушивается в родительском элементе, и выполняет обновление списка пользователей. Это изменение будет просачиваться вниз через всех детей, которые получат эти данные в качестве опоры.

Но это потребовало бы значительного переоснащения нашего миксина или даже сделало бы его почти полностью избыточным.

Почему бы вам не попробовать и не посмотреть?

Итак, могут ли примеси Vue быть полезными? Безусловно, но они требуют некоторого планирования и понимания их ограничений. Являются ли они конечными, всеми классными функциями Vue? Абсолютно нет, но всегда полезно знать, как высушить код в крайнем случае.

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

Эван — иллюстратор, разработчик, дизайнер и аниматор, который рассказывает истории любым доступным ему способом. Когда он не занимается брендингом бизнеса или созданием интерфейсных приложений; он иллюстрирует детские книги, рисует для настольных игр, анимирует рекламные ролики или разрабатывает собственные увлеченные проекты.