Перейти к содержимому
Тема 5 из 5
Теория

Компоненты и проект: конвертер

Компоненты во Vue

Как и в React, интерфейс во Vue собирают из компонентов. Компонент — объект с setup и template, а использовать его в другом компоненте можно, зарегистрировав в components:

const Hello = {
  template: `<p>Привет!</p>`,
};

const App = {
  components: { Hello },
  template: `
    <div>
      <Hello />
      <Hello />
    </div>
  `,
};

В файлах .vue то же самое пишут через import Hello from "./Hello.vue".

Props

Данные от родителя компонент объявляет в props. В шаблоне они доступны по имени, а в setup — через первый аргумент:

const UserCard = {
  props: ["name", "age"],
  setup(props) {
    const isAdult = computed(() => props.age >= 18);
    return { isAdult };
  },
  template: `
    <div class="card">
      <h3>{{ name }}</h3>
      <p v-if="isAdult">18+</p>
    </div>
  `,
};

Родитель передаёт строки как обычные атрибуты, а числа, массивы и данные из setup — через ::

<UserCard name="Аня" :age="20" />
<UserCard :name="user.name" :age="user.age" />

Без двоеточия age="20" придёт строкой "20", а не числом.

Props можно описать подробнее — с типом и значением по умолчанию:

props: {
  name: { type: String, required: true },
  age: { type: Number, default: 0 },
},

Как и в React, props только для чтения: компонент не должен их менять. props реактивен — когда родитель передаёт новое значение, компонент обновится сам.

Событие наверх: emit

Ребёнок не меняет данные родителя, а сообщает ему о событии. Родитель решает, что делать:

const Counter = {
  props: ["value"],
  emits: ["change"],
  setup(props, { emit }) {
    const inc = () => emit("change", props.value + 1);
    return { inc };
  },
  template: `<button @click="inc">{{ value }}</button>`,
};
<!-- родитель -->
<Counter :value="count" @change="count = $event" />

emit("имя", данные) вызывает обработчик @имя у родителя; переданные данные в шаблоне родителя доступны как $event. Список событий объявляют в emits — это документация для читателя кода.

Это та же схема, что в React: данные вниз через props, события вверх через emit.

Слоты

Содержимое между тегами компонента попадает в <slot> — аналог children в React:

const Card = {
  props: ["title"],
  template: `
    <section class="card">
      <h2>{{ title }}</h2>
      <slot></slot>
    </section>
  `,
};
<Card title="Новости">
  <p>Сегодня вышел Vue 3.5!</p>
</Card>

Проект: конвертер валют

Конвертер собирает весь курс:

  • ref для суммы, валют и истории;
  • v-model для поля (с .number, чтобы получить число) и списков select;
  • v-for для вариантов валют и истории;
  • computed для результата и строки «100 USD = 92 EUR»;
  • события для обмена валют местами и сохранения в историю.

Курсы задают «сколько единиц валюты за 1 доллар». Тогда любую пару считают через доллар: сначала переводим сумму в доллары (amount / rates[from]), потом в нужную валюту (× rates[to]):

const result = computed(() =>
  Math.round((amount.value / rates[from.value]) * rates[to.value] * 100) / 100
);

Обмен местами — деструктуризация: [from.value, to.value] = [to.value, from.value]. История с ограничением длины — новый массив: [новое, ...старое].slice(0, 3).

В реальном приложении курсы загружали бы с сервера в onMounted или watch с immediate, а историю сохраняли бы в localStorage через watch — всё это ты уже умеешь.

Итог

  • Компоненты регистрируют в components и используют как теги.
  • props — данные от родителя (только чтение); :prop для не-строк.
  • emit("событие", данные) — сообщить родителю; родитель слушает @событие, данные в $event.
  • <slot> — место для содержимого между тегами компонента.

Значок

Лёгкая+10 XP

Напиши компонент Badge с props label и count. Он показывает <span class="badge">label: count</span>. Если count больше 99, вместо числа показывается 99+.

Компонент App в заготовке уже использует Badge — запусти и посмотри.

<Badge label="Inbox" :count="5" />    →  Inbox: 5
<Badge label="Spam" :count="250" />   →  Spam: 99+

Подключи коннектор, чтобы решать задачи

Код задач выполняется на твоём компьютере — так быстрее и надёжнее, чем в браузере. Для этого нужна бесплатная программа-коннектор CodeWithMe. Подключить её нужно один раз.

Ищем коннектор на этом компьютере…

  1. 1
    Скачай коннектор для своей системы (Windows, macOS или Linux).Скачать коннекторНа странице загрузки выбери файл со своей системой в названии, например windows-amd64.
  2. 2Запусти его и выбери папку, где будут лежать твои решения. Python и Node.js он поставит туда сам, когда понадобится.
  3. 3
    Введи ниже код из 6 цифр — он написан в окне коннектора («Код для сайта CodeWithMe»). Если браузер спросит про доступ к локальной сети — разреши.

Коннектор открытый (исходный код на GitHub), работает только на твоём компьютере и выполняет код лишь после ввода кода сопряжения.