Урок 03

Шаблоны и интерполяция

Что такое шаблон

Шаблон Vue — обычный HTML + специальные директивы. Vue его компилирует в виртуальный DOM.

Интерполяция текста

Двойные фигурные скобки:

<template>
    <h1>{{ title }}</h1>
    <p>{{ message }}</p>
    <span>{{ count + 1 }}</span>
    <span>{{ isActive ? 'Активен' : 'Неактивен' }}</span>
</template>

Что можно:

  • Переменные
  • Выражения (без if, for)
  • Тернарные операторы
  • Вызовы методов

Нельзя:

  • Многострочный код
  • Операторы if, for

Один раз — v-once

Если данные не меняются:

<h1 v-once>{{ title }}</h1>

Что даёт: Vue не будет следить за обновлением. Экономит ресурсы.

HTML из данных — v-html

Обычно {{ }} экранирует HTML. Если нужно вставить разметку:

<template>
    <div v-html="htmlContent"></div>
</template>

<script setup>
import { ref } from 'vue';
const htmlContent = ref('<strong>Жирный</strong> текст');
</script>

⚠️ Опасно с пользовательскими данными — XSS-атаки. Используй только с доверенным контентом.

Привязка атрибутов — v-bind

Полная форма:

<img v-bind:src="imageUrl" v-bind:alt="imageAlt">

Краткая (:):

<img :src="imageUrl" :alt="imageAlt">

Динамические атрибуты:

<button :disabled="isLoading">Отправить</button>
<div :class="{ active: isActive, disabled: !isEnabled }"></div>
<div :style="{ color: textColor, fontSize: fontSize + 'px' }"></div>

Привязка классов

Объектом:

<div :class="{ active: isActive, 'text-danger': hasError }"></div>

Массивом:

<div :class="[baseClass, isActive ? 'active' : '', errorClass]"></div>

С обычным классом:

<div class="static" :class="{ active: isActive }"></div>

Привязка стилей

<div :style="{ color: 'red', fontSize: '16px' }"></div>
<div :style="styleObject"></div>
<div :style="[baseStyles, overrideStyles]"></div>

Привязка к свойствам

<input :value="message" :placeholder="placeholder">
<option :value="user.id">{{ user.name }}</option>

Булевы атрибуты

<button :disabled="isDisabled">OK</button>
<input :required="isRequired">
<input :checked="isChecked">

Если значение false — атрибут удаляется.

Несколько атрибутов через v-bind

Объектом:

<script setup>
import { ref } from 'vue';
const attrs = ref({
    id: 'my-id',
    class: 'my-class',
    'data-value': 'test',
});
</script>

<template>
    <div v-bind="attrs"></div>
</template>

Expression vs Statement

Expression — вычисляется в значение:

{{ count + 1 }}
{{ name.toUpperCase() }}
{{ items.length }}

Statement — выполняет действие:

<div @click="count++"></div>
<div @click="doSomething()"></div>

В {{ }} — только expression.

Полный пример

<template>
    <div class="card" :class="{ featured: isFeatured }">
        <h2>{{ title }}</h2>
        <p v-if="description">{{ description }}</p>
        <img :src="imageUrl" :alt="title">
        <button :disabled="isLoading" @click="buy">
            {{ isLoading ? 'Загрузка...' : 'Купить' }}
        </button>
    </div>
</template>

<script setup>
import { ref } from 'vue';

const title = ref('iPhone');
const description = ref('Новый iPhone 2026');
const imageUrl = ref('/iphone.jpg');
const isFeatured = ref(true);
const isLoading = ref(false);

function buy() {
    isLoading.value = true;
    setTimeout(() => isLoading.value = false, 1000);
}
</script>

<style scoped>
.card {
    padding: 20px;
    border: 1px solid #ddd;
}
.featured {
    border-color: gold;
}
</style>

Итог

  • {{ }} — интерполяция текста
  • v-bind:attr или :attr — привязка атрибутов
  • :class — объект/массив классов
  • :style — объект/массив стилей
  • v-html — HTML из данных (осторожно!)
  • v-once — без обновления

Дальше — директивы v-if, v-for, v-bind.