Skip to content

Фреймворк Vue 3

Современная всемирная паутина (World Wide Web) претерпела значительные изменения по сравнению с теми временами, когда Интернет представлял собой лишь набор связанных между собой страниц, предназначенных для академических и научных целей. По мере развития технологий и увеличения мощности машин к прежним протоколам добавлялись все новые и новые возможности, конкурировали новые методы и технологии, пока, наконец, не были приняты стандарты. Дополнительные возможности появились в виде плагинов для браузера и встроенного контента. Распространенными были Java-апплеты, Flash, Macromedia, Quicktime и другие плагины. Именно с появлением HTML5 большинство из них, если не все, были постепенно вытеснены стандартами.

Сегодня существует четкое различие между структурой, стилем и поведением. Язык разметки гипертекста (HTML) определяет структурные элементы, из которых состоит веб-страница. Каскадные таблицы стилей (CSS) предоставляют правила, изменяющие внешний вид HTML-элементов, включая даже анимацию и трансформацию. И, наконец, JavaScript - язык программирования, который обеспечивает поведение и может обращаться и изменять как HTML, так и CSS. Такое количество различных возможностей также привело к высокой сложности и несовместимости между браузерами. Именно здесь и зародились библиотеки и фреймворки, которые сначала решали проблемы несовместимости и стандартизации внешнего вида, но вскоре стали включать в себя и другие парадигмы программирования, выходящие за рамки простого манипулирования HTML и CSS.

Некоторые из наиболее популярных сегодня библиотек и фреймворков используют реактивную парадигму. Они умело вносят изменения в JavaScript, которые автоматически отражаются в HTML/CSS. Vue 3 - это последняя версия прогрессивного фреймворка, в котором в значительной степени используется концепция реактивности. В нем также реализованы другие парадигмы и паттерны проектирования программного обеспечения, позволяющие создавать все: от простых взаимодействий на статичной веб-странице до сложных приложений, которые могут даже устанавливаться локально и конкурировать с нативными настольными приложениями.

В этой книге мы познакомимся с фреймворком Vue 3 и изучим различные шаблоны проектирования, которые помогут нам создавать первоклассные приложения: от простых веб-страниц до мощных прогрессивных веб-приложений (PWA). Попутно мы рассмотрим лучшие практики и хорошо зарекомендовавшие себя паттерны в программной инженерии.

В этой главе рассматриваются следующие темы:

  • Прогрессивный фреймворк
  • Однофайловые компоненты
  • Различные варианты синтаксиса для написания компонентов

К концу этой главы вы будете иметь базовое представление о том, какое место Vue 3 занимает в ландшафте JavaScript и какие возможности он предоставляет. Для пользователей Vue 2 в этой книге есть приложение, в котором описаны изменения, на которые необходимо обратить внимание при переносе приложения. По мере продвижения по книге мы будем наращивать знания на основе этих концепций.

Прогрессивный фреймворк

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

Выбирая тот или иной вариант для создания веб-приложения, мы должны понимать, что это такое.

Давайте рассмотрим определения этих терминов:

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

Разделив понятия, теперь возникает вопрос, когда использовать библиотеку, а когда фреймворк. Прежде чем ответить на этот вопрос, давайте поймем, что при создании реальных приложений между ними существует огромная "серая зона". Теоретически одно и то же приложение можно построить, используя любой из этих двух вариантов. Как и всегда в программной инженерии, необходимо определиться с компромиссами для каждого подхода. Так что воспринимайте то, что будет написано дальше, с щепоткой соли; это не закон, написанный на камне:

  • Вы можете использовать библиотеку при создании приложений малого и среднего размера или при необходимости добавления дополнительной функциональности в приложение (в общем случае, вы можете использовать дополнительные библиотеки внутри фреймворков). Существуют и исключения из правила "размера". Например, React - это библиотека, но на ее основе построены огромные приложения, такие как Facebook. Компромисс заключается в том, что использование только библиотек без фреймворка потребует выработки общих подходов и большей координации внутри команды, поэтому усилия по управлению и руководству могут значительно возрасти. С другой стороны, библиотека, используемая в рамках обычного программирования на JavaScript, может предложить некоторые важные улучшения производительности и обеспечить значительную гибкость.
  • Вы можете захотеть использовать фреймворк при создании приложений среднего и большого размера, когда вам нужна структура, помогающая координировать разработку, или когда вы хотите быстро начать, минуя "азы" разработки общей функциональности с нуля. Существуют фреймворки, построенные поверх других фреймворков, например, Nuxt построен поверх Vue. Компромисс заключается в том, что для построения приложения вам предписывается архитектурная модель, которая часто соответствует определенному подходу и образу мышления. Вам и вашей команде придется изучить фреймворк и его ограничения и жить в этих границах. Всегда есть вероятность того, что в будущем ваше приложение может перерасти рамки. В то же время некоторые из преимуществ таковы: более легкая координация работы, значительный выигрыш от стартового рывка, верное и проверенное решение общих проблем, ориентация на конкретные ситуации (например, торговые приложения в сравнении с социальными сетями) и многое другое. Однако в зависимости от фреймворка вы можете столкнуться с небольшим снижением производительности за счет дополнительной обработки данных или трудностями масштабирования. Вам предстоит взвесить компромиссы в каждом конкретном случае.

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

Еще одной фундаментальной концепцией Vue является реактивность. Она подразумевает возможность автоматического отображения в HTML значения или изменений, внесенных в переменную в JavaScript, а также внутри вашего кода. В этом заключается большая часть волшебства, предлагаемого Vue.

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

sh
A = B + C

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

В следующих главах мы будем изучать этот прогрессивный атрибут в процессе создания примеров приложений. Но перед этим нам нужно посмотреть, что предлагает Vue 3 в самом базовом виде.

Использование Vue в веб-приложении

Существует несколько вариантов использования Vue в веб-приложении, и это во многом зависит от того, какую цель вы преследуете:

  • Для размещения на странице небольшого автономного приложения или фрагмента кода можно напрямую импортировать Vue и код внутри тега script
  • Для создания более крупного приложения вам понадобится инструмент сборки, который возьмет ваш код и соберет его для распространения

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

Давайте кратко рассмотрим пример первого случая на примере очень простой HTML-страницы:

html
<html>
  <head>         
    <script src="https://unpkg.com/vue@3"></script>
  </head>
  <body>
        
    <div id="app">{{ message }}</div>
    <script>
      const { createApp } = Vue;
      createApp({
        data() {
          return { message: "Hello World!" };
        },
      }).mount("#app");
    </script>
  </body>
</html>

В разделе head мы определяем тег script и импортируем Vue из бесплатной сети доставки контента (CDN). При этом создается глобальная переменная Vue, которая открывает все методы и функции фреймворка. Внутри нашего тега body мы объявляем элемент div с id="app". Это определяет, где будет размещено наше небольшое приложение и какой частью страницы будет управлять фреймворк Vue. Обратите внимание на содержимое div: . Двойные фигурные скобки определяют точку, в которой содержимое будет заменено во время выполнения на значение переменной message, которую мы определяем в JavaScript. Это называется интерполяцией и является основным способом отображения значения (строки, числа и т.д.) на веб-странице.

В конце body мы создаем элемент сценария с нашим приложением. В начале мы извлекаем из Vue функцию createApp и используем ее для создания приложения, передавая объект. Этот объект имеет определенные поля, которые определяют компонент. В данном случае этот компонент раскрывает только метод data(), который, в свою очередь, возвращает объект. Имена полей в этом объекте будут рассматриваться как реактивные переменные, которые мы можем использовать как в JavaScript, так и в HTML. Наконец, конструктор createApp() возвращает экземпляр приложения Vue 3, поэтому мы передаем вызов по цепочке и вызываем метод mount(), чтобы смонтировать наше скромное приложение на элемент с идентификатором app. Обратите внимание, что в качестве аргумента мы используем CSS-селекторы (знак "решётки" указывает на аттрибут id, следовательно, id="app" выбирает #app).

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

Путь сборщика, лучший путь...

Как вы можете себе представить, импортировать Vue непосредственно в веб-страницу можно только для очень маленьких приложений. Вместо этого Vue построен на концепции компонентов, которые представляют собой многократно используемые изолированные наборы JavaScript-кода, HTML и CSS, ведущие себя как единое целое. Их можно рассматривать как строительные блоки для создания веб-страницы. Очевидно, что браузер ничего об этом не знает, поэтому мы будем использовать сборщик (bundler) для преобразования нашего приложения в то, что браузер может интерпретировать, с дополнительным преимуществом - выполнением ряда оптимизаций в процессе. Именно здесь вступает в действие "фреймворк", который предписывает, как должны быть написаны эти компоненты и какие методы должны содержать.

При использовании сборщика весь наш код будет упакован в один или несколько JavaScript-файлов, которые браузер будет загружать во время выполнения. Рабочий процесс выполнения в браузере для приложения Vue можно изобразить следующим образом:

Рисунок 1.1: Очень упрощенный вид порядка выполнения нашего приложения
при использовании сборщика

Рисунок 1.1: Очень упрощенное представление порядка выполнения нашего приложения при использовании сборщика

Браузер, как обычно, загрузит страницу index.html, а затем загрузит и выполнит файл bundle.js, как и любой другой JavaScript. Сборщик упакует все наши файлы и выполнит их в заданном порядке:

  1. Файл main.js импортирует и запускает приложение Vue 3.
  2. Затем начнется композиция страницы из главного компонента, заключенного в файл App.vue. Этот компонент порождает другие компоненты, формируя таким образом дерево компонентов, из которых состоит страница.

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

До сих пор вы имели представление о том, что такое библиотеки и фреймворки, и лишь бегло ознакомились с тем, что предлагает Vue. Важно помнить, что в современном мире JavaScript принято использовать сборщики, которые помогают нам организовать наши приложения и оптимизировать код для браузера. В дальнейшем мы будем работать с официальным сборщиком Vue 3, Vite. Но сначала нам нужно знать еще несколько базовых понятий.

Понимание однофайловых компонентов

Как вы уже догадались, файл App.vue, упомянутый ранее, представляет собой однофайловый компонент (SFC), что является одним из главных достижений Vue. В файле этого типа мы можем описать HTML, CSS и JavaScript, определяющие компонент. Веб-страница состоит из иерархии компонентов, начиная с точки входа (традиционно называемой App.vue) и заканчивая последней настраиваемой кнопкой, если хотите. Более подробно о компонентах мы поговорим в главе 4 Композиция пользовательского интерфейса с помощью компонентов, а пока запомните, что это путь, предписанный фреймворком. Если у вас есть опыт работы с объектно-ориентированными языками, это может показаться вам знакомым (и вы не ошибетесь).

SFC - это обычный текстовый файл с расширением .vue, содержащий следующие секции:

vue
<script setup>
// Here we write our JavaScript
</script>

<template>      
  <h1>Hello World! This is pure HTML</h1>
</template>

<style scoped>
h1 {
  color: purple;
}
</style>

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

  • Тег script, который окружает наш JavaScript и, в зависимости от синтаксиса, экспортирует объект с четко определенными полями. На практике это превращается в модуль, который является современным способом разделения кода в JavaScript. Обратите также внимание, что мы используем атрибут-модификатор setup. Он определяет интерфейс приложения, который мы будем использовать для написания нашего кода на Vue. Мы также можем объявить атрибут lang="ts", чтобы использовать TypeScript вместо обычного JavaScript.
  • Тег template окружает HTML для нашего компонента. Здесь мы можем использовать элементы HTML, другие компоненты, директивы и т. д. Большим преимуществом Vue является то, что мы можем использовать обычный HTML для написания нашего HTML. Это может показаться очевидным, но другие библиотеки работают с этим совершенно иначе и имеют свой собственный синтаксис для этого. Однако Vue 3 позволяет использовать и другие синтаксисы с помощью плагинов сборщика. Здесь у нас есть опции.
  • Тег style, в котором мы разместим CSS для нашего компонента. В данном случае мы используем атрибут scoped, который инкапсулирует правила и ограничивает их рамками нашего компонента, тем самым предотвращая их "утечку" в остальное приложение. Как и в предыдущих разделах, мы также можем использовать различный синтаксис для написания стилей, если он поддерживается сборщиком.

Хорошая практика

Всегда используйте scoped стили, если только вы не определяете стили для родительского компонента или CSS-переменные, которые вы хотите передать всему приложению в явном виде. Для стилей, распространяющихся на все приложение, используйте отдельный CSS-файл.

Важно помнить, что SFC содержит эти три элемента, определяющие один компонент. Сборщик сделает свою магию, отделит каждую часть и поместит ее туда, где она должна быть, чтобы браузер мог правильно интерпретировать ее. Мы будем использовать для этого быстрый и новый Vite в главе 3 Установка рабочего проекта, и в главе 4 Композиция пользовательского интерфейса с компонентами, мы подробно рассмотрим компоненты и то, как управлять потоком программы и информацией между ними. Но сначала давайте рассмотрим, как мы пишем наши компоненты.

Разные варианты - options, composition, и script setup API

Классический способ описания компонента в Vue 2 получил название Options API. Для сохранения обратной совместимости этот же синтаксис поддерживается и в Vue 3. Однако существует и новый синтаксис, названный Composition API, который мы и будем использовать в этой книге.

Options API унаследован от Vue 2 и предписывает, что компонент определяется объектом с определенными полями, ни одно из которых не является обязательным. Более того, некоторые из них имеют определенные параметры и ожидаемые выходы. Например, вот наиболее часто используемые поля (список также не является исчерпывающим):

  • data - должна быть функцией, возвращающей объект, поля которого станут реактивными переменными.
  • methods - это объект, содержащий наши функции. Эти функции имеют доступ к реактивным переменным из data, используя формат this.variableName
  • components - объект, каждое поле которого содержит имя шаблона, а значение указывает на конструктор другого компонента (дочернего по отношению к текущему).
  • computed - это объект, атрибуты которого определяют "вычисляемые" свойства. Каждый член - это функция или объект, который может быть использован в качестве реактивных переменных в нашем шаблоне и коде. Функции будут доступны только для чтения, а объекты могут содержать логику для чтения и записи в них значений. Эта концепция будет проясняться по мере просмотра примеров кода в главе 3 Установка рабочего проекта.
  • props и emits объявляют параметры для получения данных от родительского компонента и объявляют события, отправляемые родительскому компоненту. Это обеспечивает формальный способ связи и передачи данных между связанными компонентами, но не единственный, как мы увидим в главе 7 Управление потоком данных.
  • life cycle hooks - это ряд функций, которые запускаются в течение жизненного цикла компонента.
  • миксины - это объекты, описывающие общую функциональность, которая может быть использована совместно в нескольких компонентах. Это не единственный способ повторного использования кода в Vue 3. Использование миксинов в API Options вызвало некоторые сложности, которые привели к появлению API Composition. Мы не будем подробно рассматривать миксины, но рассмотрим другие подходы к обмену функциональностью между компонентами (например, "composables").

Этот синтаксис хорошо определен, но имеет ряд ограничений. Для небольших компонентов он слишком сильно загромождает код, а для больших компонентов организация кода сильно страдает и получается очень многословной. Кроме того, для обращения к реактивным переменным, объявленным в секции data, или к другим методам во внутреннем коде приходится использовать ключевое слово this (например, this.data_variable_name или this.myMethod()). Ключевое слово this относится к созданному экземпляру компонента. Проблема заключается в том, что зарезервированное слово this меняет значение в зависимости от области и контекста использования. Есть и другие недостатки, проявившиеся со временем, которые привели к созданию Composition API. Однако данный синтаксис актуален и полностью поддерживается в Vue 3. Одним из его преимуществ является возможность легкой миграции кода из Vue 2 (с определенными оговорками, как показано далее в Приложении - Миграция из Vue 2).

Composition API предоставляет метод setup(), который выполняется перед установкой компонента. В этом методе мы импортируем функции и компоненты, объявляем переменные и т.д., которые определяют наш компонент, вместо того чтобы объявлять их как "опции". Это означает, что вы можете писать свой код в бОльшей степени как на обычном JavaScript. Это дает вам свободу импортировать, повторно использовать и лучше организовывать свой код.

Давайте сравним эти два подхода на примере реактивной переменной, _hello="Hello World":

Options API

vue
<script>
export default {
  data() {
    return { _hello: "Hello World" };
  },
};
</script>

Composition API

vue
<script>
import { ref } from "vue";
export default {
  setup() {
    const _hello = ref("Hello World");
    return { _hello };
  },
};
</script>

В Options API мы просто используем поле data, чтобы вернуть объект, поля которого превратятся в реактивные переменные. Vue позаботится об интерпретации этого объекта. Однако обратите внимание, что в Composition API нам необходимо сначала импортировать из Vue конструктор ref, который создаст для нас реактивную константу или переменную. Конечный результат тот же, но здесь мы имеем более тонкий контроль над тем, что и где делается. При использовании нового сборщика Vite такой тонкий контроль над тем, что импортируется в наши компоненты, может привести к ускорению процесса создания кода и времени разработки.

На первый взгляд кажется, что Composition API более многословен, чем Options API, и так оно и есть для такого тривиального примера. Однако по мере роста нашего компонента все становится наоборот. Но все равно, многословность... Но существует альтернативный синтаксис для Composition API, называемый script setup, и именно его мы будем использовать в этой книге. Давайте теперь сравним, как выглядит этот компонент с новым синтаксисом:

Composition API - script setup

vue
<script setup>
import { ref } from "vue";
const _hello = ref("Hello World");
</script>

Две строки кода! Это трудно превзойти. Поскольку мы добавили атрибут setup в тег script, сборщик знает, что все, что мы здесь делаем, относится к области Composition API, и все функции, переменные и константы автоматически отображаются в шаблон. Нет необходимости определять экспорт. Если нам что-то нужно, мы импортируем это напрямую и используем. Кроме того, теперь у нас есть несколько дополнительных преимуществ, например, следующие:

  • Мы можем иметь реактивные и нереактивные переменные, отображаемые в нашем шаблоне
  • Мы знаем, что весь код выполняется до того, как компонент будет смонтирован
  • Синтаксис ближе к ванильному JavaScript (большой плюс!!!), поэтому мы можем организовать наш код так, как нам удобно и приятно
  • Меньший размер пакета (я уже говорил об этом? Да, это важно!)

Но подождите, вы можете заметить, что я определяю реактивную переменную как константу! Да, это так. И нет, это не ошибка. В JavaScript константа указывает на конкретное неизменяемое значение, которым в данном случае является объект, но это относится только к объекту, а не к его членам. Конструктор ref() возвращает объект, поэтому константа применяется к ссылке на объект, и мы можем изменять значения его членов. Если вы работали с указателями в Java, C или другом подобном языке, то, возможно, узнаете эту концепцию как использование указателей. Однако за все это приходится платить. Для того чтобы получить доступ к значению и изменить его, теперь необходимо получить доступ к атрибуту значение объекта. Вот пример:

js
_hello.value = "Некоторое другое значение";

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

vue
<div>{{ _hello }}</div>

Кроме того, каждый раз, когда переменная объявляется как реактивная с помощью конструктора ref(), необходимо ссылаться на ее значение в формате constant_name.value, и как constant_name в шаблоне (HTML). Когда имя константы используется в шаблоне, Vue уже знает, как получить доступ к ее значению, и вам не нужно ссылаться на нее явно, как в JavaScript.

Совет

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

Изучение встроенных директив в Vue 3

В Vue также предусмотрены специальные атрибуты HTML, называемые директивами. Директива объявляется в открывающем теге HTML-элемента и влияет на динамическое поведение или функциональность этого элемента. Мы также можем создавать собственные директивы в Vue. Те из них, которые предоставляются фреймворком, имеют специальную нотацию, начинающуюся с v-. В рамках данной книги рассмотрим наиболее часто используемые директивы Vue:

v-bind: (сокращение ":")

Директива v-bind: связывает значение HTML-атрибута со значением переменной JavaScript. Если переменная является реактивной, то каждое обновление её значения будет отражаться в html. Если переменная не реактивная, то она будет использоваться только один раз при первоначальном рендеринге HTML. Чаще всего мы используем только сокращенный префикс : (двоеточие). Например, реактивная переменная my_profile_picture содержит веб-адрес к картинке:

html
<img :src="my_profile_picture" />

Атрибут src получит значение переменной my_profile_picture

v-show

Эта директива показывает или скрывает элемент, не удаляя его из документа. Она эквивалентна модификации атрибута CSS display. Она ожидает переменную, которая дает булево значение (или то, что может быть интерпретировано как true или непустое). Например, переменная loading имеет булево значение:

vue
<div v-show="loading">...</div>

Этот div появится, когда переменная loading будет равна true.

Важно иметь в виду, что v-show будет использовать стиль объекта, чтобы отобразить его или нет, но элемент все равно будет частью Document Object Model (DOM)

v-if, v-else и v-else-if

Эти директивы ведут себя так же, как и условные предложения в JavaScript, показывая и скрывая элемент в зависимости от значения, определяемого переданным выражением. Они похожи на v-show в том смысле, что показывают или скрывают элемент, но с той разницей, что они полностью удаляют элемент из DOM. Из-за этого при неправильном использовании в больших масштабах с элементами, часто меняющими свое состояние, они могут быть дороги в вычислительном отношении, так как фреймворку приходится выполнять больше операций для манипулирования DOM, в отличие от v-show, когда нужно изменить только стиль отображения.

Совет

Используйте v-if для показа или отображения элементов, которые не будут переключаться после показа или скрытия (и предпочтительно, если начальное состояние скрыто). Используйте v-show, если элемент будет часто показываться/скрываться. Это улучшит производительность при отображении больших списков элементов.

v-for и :key

В сочетании эти два атрибута ведут себя подобно циклу for в JavaScript. Они создают столько копий элемента, сколько прописано в итераторе, каждая из которых имеет соответствующее интерполированное значение. Это очень удобно для отображения коллекций элементов данных. Атрибут :key используется внутри цикла для более эффективного отслеживания изменений и должен ссылаться на уникальный атрибут элемента, по которому выполняется цикл - например, на поле id объекта или на индекс в массиве, если индексы не меняются. Вот пример:

vue
<span v-for="i in 5" :key="i">{{ i }}</span>

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

1 2 3 4 5

v-model

Эта директива - чистая магия. При присоединении к элементу ввода (input, textarea, select и т.д.) она присваивает значение, возвращаемое HTML-элементом, ссылаемой переменной, поддерживая тем самым синхронизацию состояния DOM и JavaScript, что называется двусторонним связыванием. Вот пример:

vue
<input type="text" v-model="name">

Когда пользователь вводит текст в HTML, переменной name в JavaScript сразу же присваивается это значение. В этих примерах мы используем примитивные типы данных, такие как числа и строки, но мы можем использовать и более сложные значения, такие как объекты или массивы. Подробнее об этом будет рассказано в главе 4 Композиция пользовательского интерфейса с компонентами, когда мы рассмотрим компоненты в деталях.

v-on: (и сокращение @)

Эта директива ведет себя несколько иначе, чем предыдущие. Она ожидает не переменную, а функцию или выражение, и связывает HTML-событие с функцией JavaScript для его выполнения. Событие должно быть объявлено сразу после двоеточия. Например, чтобы отреагировать на событие click на кнопке мыши, мы напишем следующее:

vue
<button v-on:click="printPage()">Print</button>

Когда кнопка вызывает событие click, будет выполнена функция JavaScript printPage(). Кроме того, для этой директивы чаще используется сокращение, которое мы и будем использовать в дальнейшем в этой книге: просто замените v-on: на @. Тогда предыдущий пример превратится в следующий:

vue
<button @click="printPage()">Print</button>

Полный список встроенных директив можно найти в официальной документации здесь: https://vuejs.org/api/built-in-directives.html. По мере продвижения вперед мы увидим и другие.

До сих пор мы видели, что приложения Vue 3 строятся с помощью компонентов, которые мы можем использовать в нашем HTML и которые мы создаем с помощью SFC. Фреймворк также предоставляет нам директивы для работы с элементами HTML, но это еще не все. В следующем разделе мы увидим, что фреймворк также предоставляет несколько удобных готовых компонентов, которые мы можем использовать.

Встроенные компоненты

Фреймворк также предоставляет нам несколько встроенных компонентов, которые мы можем использовать, не импортируя их явно в каждый SFC. Я привел здесь небольшое описание каждого из них, поэтому за синтаксисом и примерами можно обратиться к официальной документации (см. https://vuejs.org/api/built-in-components.html):

  • Transition и TransitionGroup - это два компонента, которые могут работать вместе для обеспечения анимации и перехода элементов и компонентов. Они требуют создания CSS-анимации и классов переходов для реализации анимации при вставке или удалении элементов на странице. В основном (или часто) они используются при отображении списка элементов с помощью директив v-for/:key или v-if/v-show.

  • KeepAlive - это еще один компонент-обертка (то есть окружение других компонентов), используемый для сохранения состояния (внутренних переменных, элементов и т.д.), когда компонент, обернутый в него, больше не отображается. Обычно при размонтировании экземпляры компонентов очищаются и "собираются в мусор". KeepAlive сохраняет их в кэше, чтобы их состояние было восстановлено, когда они снова появятся на экране.

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

  • Suspense - новый компонент в Vue 3, но пока он находится в экспериментальной стадии, поэтому его будущее на момент написания статьи не определено. Основная идея заключается в отображении "запасного" контента до тех пор, пока все асинхронные дочерние компоненты/элементы не будут готовы к рендерингу. Он предоставляется для удобства, поскольку существуют шаблоны, которые можно использовать для решения этой проблемы. Мы рассмотрим их позже.

  • Component-is - это специальный элемент, который будет загружать компонент во время выполнения, как предписано содержимым переменной - например, если нам нужно отобразить компонент на основе значения переменной, а использование других директив может быть громоздким. Она также может быть использована для вывода HTML-элементов. Рассмотрим пример:

vue
<script setup>
import EditItem from "EditItem.vue";
import ViewItem from "ViewItem.vue";
import { ref } from "vue";
const action = ref("ViewItem");
</script>

<template>     
  <component :is="action"></component>     
  <button @click="action = 'EditItem'">Edit</button>
</template>

В этом простом примере, когда пользователь нажмет кнопку Edit, значение action изменится на EditItem, и компонент заменится. Документацию можно найти здесь:https://vuejs.org/api/built-in-special-elements.html.

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

Кодовые соглашения (code conventions) в книге

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

Переменные и пропсы

Они всегда пишутся в нижнем регистре, а пробелы заменяются знаком подчеркивания, например, total_count и person_id.

Константы

Ссылки на инжектируемые объекты начинаются со знака $, например, $router, $modals и $notifications.

Ссылки на реактивные данные начинаются с _ и набираются в змеином регистре (snake case), например, _total и _first_input.

Ссылки на константные значения обозначаются заглавными буквами, например, OPTION и LANGUAGE_CODE.

Функции-конструкторы для инжектируемых зависимостей будут начинаться с use, например, const $store=useStore().

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

Они записываются в PascalCase (каждое слово начинается с буквы верхнего регистра), например, Person, Task и QueueBuilder.

Функции, методы, события и имена файлов

Они пишутся в CamelCase, например, doSubscribe() и processQueue().

Экземпляры

Экземпляры будут иметь абстрактное имя, за которым следует слово Service в случае обычных JavaScript-объектов, предоставляющих функции, Model для моделей состояний и так далее. Мы будем использовать сервисы для инкапсуляции функциональности.

Например: const projectService=new ProjectService().

Совет

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

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

Подведение итогов

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

Вопросы для проверки

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

  • В чем разница между библиотекой и фреймворком?
  • Почему Vue является "прогрессивным" фреймворком?
  • Что такое однофайловые компоненты?
  • Какие директивы наиболее часто используются при разработке Vue?
  • Почему важны соглашения в коде?

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