← Курс/Template синтаксис Vue#201 из 257+30 XP

Template синтаксис Vue

Mustache — вывод данных

Самый базовый способ вывести данные в шаблоне — двойные фигурные скобки **{{ }}**:

<template>
  <p>{{ message }}</p>
  <p>{{ count + 1 }}</p>
  <p>{{ isOk ? 'Да' : 'Нет' }}</p>
  <p>{{ text.toUpperCase() }}</p>
</template>

<script setup>
import { ref } from 'vue'
const message = ref('Привет!')
const count = ref(5)
const isOk = ref(true)
const text = ref('hello')
</script>

Внутри {{ }} можно писать любое JavaScript-**выражение** (но не инструкцию).

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

Для динамических атрибутов используется директива v-bind (сокращение — :):

<template>
  <!-- Полная форма -->
  <img v-bind:src="imageUrl" v-bind:alt="imageAlt">

  <!-- Сокращённая форма (используется чаще) -->
  <img :src="imageUrl" :alt="imageAlt">

  <!-- Привязка класса -->
  <div :class="{ active: isActive, error: hasError }">...</div>

  <!-- Привязка стилей -->
  <div :style="{ color: textColor, fontSize: size + 'px' }">...</div>
</template>

v-if, v-else-if, v-else — условный рендеринг

<template>
  <div v-if="score >= 90">Отлично</div>
  <div v-else-if="score >= 70">Хорошо</div>
  <div v-else-if="score >= 50">Удовлетворительно</div>
  <div v-else>Неудовлетворительно</div>
</template>

**v-show** — альтернатива v-if. Элемент всегда рендерится, но скрывается через display: none:

<!-- v-if удаляет элемент из DOM -->
<div v-if="isVisible">Я либо есть, либо меня нет в DOM</div>

<!-- v-show скрывает через CSS, элемент остаётся в DOM -->
<div v-show="isVisible">Я всегда в DOM, просто скрыт</div>

Используйте v-show если элемент часто переключается, v-if — если условие редко меняется.

v-for — рендеринг списков

<template>
  <!-- Массив -->
  <ul>
    <li v-for="item in items" :key="item.id">
      {{ item.name }}
    </li>
  </ul>

  <!-- Массив с индексом -->
  <ul>
    <li v-for="(item, index) in items" :key="item.id">
      {{ index + 1 }}. {{ item.name }}
    </li>
  </ul>

  <!-- Объект -->
  <ul>
    <li v-for="(value, key) in userInfo" :key="key">
      {{ key }}: {{ value }}
    </li>
  </ul>
</template>

Атрибут :key обязателен — Vue использует его для эффективного обновления списка.

v-model — двусторонняя привязка

v-model синхронизирует значение элемента формы с реактивной переменной:

<template>
  <input v-model="username" placeholder="Введите имя">
  <p>Имя: {{ username }}</p>

  <input type="checkbox" v-model="isChecked"> Согласен
  <p>Статус: {{ isChecked ? 'согласен' : 'не согласен' }}</p>

  <select v-model="selectedCity">
    <option value="moscow">Москва</option>
    <option value="spb">Санкт-Петербург</option>
  </select>
  <p>Выбранный город: {{ selectedCity }}</p>
</template>

<script setup>
import { ref } from 'vue'
const username = ref('')
const isChecked = ref(false)
const selectedCity = ref('moscow')
</script>

v-on — обработка событий

Директива v-on (сокращение — @) добавляет обработчики событий:

<template>
  <button @click="handleClick">Нажми</button>
  <button @click="count++">Инлайн</button>
  <input @keyup.enter="submit">
  <form @submit.prevent="handleSubmit">...</form>
</template>

<script setup>
import { ref } from 'vue'
const count = ref(0)

function handleClick() {
  console.log('Клик!')
}
function submit() {
  console.log('Enter нажат')
}
function handleSubmit() {
  console.log('Форма отправлена (без перезагрузки страницы)')
}
</script>

Примеры

Простой шаблонизатор — функция template(str, data) заменяет {{key}} на значения из объекта

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

function template(str, data) {
  return str.replace(/{{\s*(\w+)\s*}}/g, (match, key) => {
    // match — всё совпадение: "{{ name }}"
    // key — первая группа захвата: "name"
    return key in data ? data[key] : match
  })
}

// --- Примеры ---

const greeting = template('Привет, {{ name }}! Тебе {{ age }} лет.', {
  name: 'Алексей',
  age: 25
})
console.log(greeting)
// Привет, Алексей! Тебе 25 лет.

// Пробелы вокруг ключа не важны
const msg = template('{{city}} — красивый город', { city: 'Москва' })
console.log(msg)
// Москва — красивый город

// Неизвестный ключ остаётся как есть
const partial = template('{{ greeting }}, {{ unknown }}!', { greeting: 'Здравствуй' })
console.log(partial)
// Здравствуй, {{ unknown }}!

// Шаблон списка (более сложный случай)
function renderList(items, itemTemplate) {
  return items.map(item => template(itemTemplate, item)).join('\n')
}

const users = [
  { name: 'Анна', role: 'admin' },
  { name: 'Борис', role: 'user' },
  { name: 'Вера', role: 'moderator' },
]

const list = renderList(users, '- {{ name }} ({{ role }})')
console.log('\nСписок пользователей:')
console.log(list)
// - Анна (admin)
// - Борис (user)
// - Вера (moderator)