Рендеринг синтаксиса шаблонов

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


Интерполяционное выражение {{ }}

Интерполяционное выражение — самый базовый способ привязки данных в Vue.

Оно «вставляет» значение переменной JS в HTML. Синтаксис — двойные фигурные скобки, окружающие имя переменной.

Пример

<script setup>
const blogTitle = 'ПРИМЕР Заметки по фронтенду'
const author = 'Сяо Мин'
</script>

<template>
  <h1>{{ blogTitle }}</h1>
  <p>Автор: {{ author }}</p>
  <p>Текущее время: {{ new Date().toLocaleDateString() }}</p>
</template>

Страница отобразит:

EXAMPLE 前端笔记
作者:小明
当前时间:2024/5/15

Внутри фигурных скобок можно поместить любое JS-выражение: переменные, операции, тернарные выражения, вызовы функций — всё это допустимо, но нельзя помещать инструкции (такие какif、for)。

Интерполяционное выражение заменяет только текст внутри тега, а не сам тег. Например,

{{ content }}
in
сам тег не затрагивается.


Привязка атрибутов v-bind (сокращённо :)

Интерполяционные выражения можно использовать только для содержимого тега, а не для HTML-атрибутов.

Чтобы использовать JS-переменные в атрибутах, нужно использовать директивуv-bind.

Пример

<script setup>
const coverUrl = '/images/vue-cover.png'
const linkUrl = '/post/1'
const isActive = true
</script>

<template>
  <!-- Полный синтаксис: v-bind:attribute="variable" -->
  <img v-bind:src="coverUrl" v-bind:alt="Обложка статьи">

  <!-- Сокращённая запись: напрямую используйте :attribute="variable" -->
  <a :href="linkUrl">Читать статью полностью</a>

  <!-- Динамический класс: используйте синтаксис объекта -->
  <div :class="{ active: isActive, 'text-bold': true }">
У этого текста есть оба класса: active и text-bold.
  </div>
</template>

Сокращение с двоеточием— самый распространённый синтаксис; в реальной разработке вы почти никогда не используетеv-bind:полное имя.


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

Главная страница блога должна отображать несколько статей. Одна статья — это объект, а несколько статей образуют массив объектов.

v-forВы можете перебирать массив и генерировать соответствующий HTML для каждого элемента.

Пример

<script setup>
// Использовать массив JS-объектов для имитации данных статей (позже будет заменено на загрузку из JSON-файла)
const articles = [
  {
    id: 1,
title: 'Полное руководство по началу работы с Vue3',
summary: 'Изучите Vue3 Composition API с нуля, охватывая основные концепции, такие как ref, reactive, computed.',
    date: '2024-05-10',
    category: 'Vue',
    cover: '/images/vue.png'
  },
  {
    id: 2,
title: 'Асинхронное программирование на JavaScript: объяснение',
summary: 'Разберитесь с Promise, async/await, event loop и очередью микрозадач в одной статье.',
    date: '2024-05-08',
    category: 'JavaScript',
    cover: '/images/js.png'
  },
  {
    id: 3,
title: 'CSS Grid Layout на практике',
summary: 'Легко реализуйте сложные адаптивные макеты с помощью CSS Grid, оставив позади ограничения float и flexbox.',
    date: '2024-05-05',
    category: 'CSS',
    cover: '/images/css.png'
  }
]
</script>

<template>
  <div class="article-list">
    <!-- v-for="item in array" :key="уникальный идентификатор" -->
    <div v-for="article in articles" :key="article.id" class="card">
      <img :src="article.cover" :alt="article.title">
      <div class="card-body">
        <span class="category">{{ article.category }}</span>
        <h3>{{ article.title }}</h3>
        <p>{{ article.summary }}</p>
        <span class="date">{{ article.date }}</span>
      </div>
    </div>
  </div>
</template>

<style scoped>
.article-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 24px;
  margin-top: 20px;
}

.card {
  background: #fff;
  border-radius: 12px;
  overflow: hidden;
  box-shadow: 0 2px 12px rgba(0,0,0,0.08);
  transition: transform 0.2s;
}

.card:hover {
  transform: translateY(-4px);
}

.card img {
  width: 100%;
  height: 180px;
  object-fit: cover;
}

.card-body {
  padding: 16px;
}

.category {
  display: inline-block;
  padding: 2px 10px;
  background: #E8EEF5;
  color: #427DB8;
  border-radius: 12px;
  font-size: 12px;
}

.card-body h3 {
  margin: 10px 0 8px;
  font-size: 18px;
}

.card-body p {
  color: #666;
  font-size: 14px;
  line-height: 1.6;
}

.date {
  display: block;
  margin-top: 10px;
  font-size: 12px;
  color: #999;
}
</style>

Важность атрибута key

:keyЭто важный спутник v-for, сообщающий Vue идентичность каждого элемента.

Когда порядок массива изменяется (например, вставка, удаление, сортировка), Vue использует key, чтобы определить, какие DOM-узлы нужно обновить, а какие можно переиспользовать.

Значение keyПоследствие
Уникальный id (рекомендуется)Правильно отслеживает каждый элемент и эффективно обновляет
Индекс массиваМожет вызвать путаницу в состоянии при вставке/удалении (например, содержимое полей ввода меняется местами)
Нет keyКонсоль выдаст предупреждение; Vue по умолчанию использует стратегию «обновление на месте», которая имеет низкую производительность.

Всегда указывайте для v-for уникальный и стабильный key; не используйте index в качестве key. Это одна из самых важных привычек в разработке на Vue.


Условный рендеринг v-if / v-else

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

Пример

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

const articles = ref([]) // список статей (пустой массив означает, что данных пока нет)
const isLoading = ref(true) // состояние загрузки
// Имитация загрузки данных: заполняем данные через 2 секунды
setTimeout(() => {
  articles.value = [
{ id: 1, title: 'Начало работы с Vue3', summary: '...' },
{ id: 2, title: 'Сравнение с React', summary: '...' }
  ]
  isLoading.value = false
}, 2000)
</script>

<template>
  <div>
    <!-- Загрузка -->
    <p v-if="isLoading">Загрузка, пожалуйста, подождите...</p>

    <!-- Показываем список, когда есть данные -->
    <div v-else-if="articles.length > 0">
      <div v-for="article in articles" :key="article.id" class="card">
        <h3>{{ article.title }}</h3>
        <p>{{ article.summary }}</p>
      </div>
    </div>

    <!-- Показываем пустое состояние, когда данных нет -->
    <p v-else>Пока нет статей, следите за обновлениями.</p>
  </div>
</template>

Этот шаблон охватывает три наиболее распространённых состояния UI:Загрузка → Есть данные → Нет данных。

v-if vs v-show

ДирективаМетод переключенияЗатраты на начальный рендерингЗатраты на переключениеСценарии использования
v-ifДобавляет/удаляет DOM-узлыНизкие (не рендерится)Высокие (перестраивает DOM)Сценарии, где условие редко меняется, например контроль прав доступа
v-showПереключает CSS-свойство displayВысокие (всегда рендерится)Низкие (меняет только стили)Сценарии с частым переключением, например переключение вкладок

Легко запомнить: используйте v-show для частого переключения, а v-if — для стабильных условий.


Практика: Готовая главная страница блога

Объедините синтаксис шаблонов, изученный ранее, и напишите полноценный компонент главной страницы блога.

Пример

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

// Данные статей (сейчас жёстко закодированы; в следующих главах это будет изменено на загрузку через fetch)
const articles = ref([
  {
    id: 1,
title: 'Полное руководство по началу работы с Vue3',
summary: 'Изучите Vue3 Composition API с нуля, охватывая основные концепции, такие как ref, reactive, computed.',
    date: '2024-05-10',
    category: 'Vue',
    cover: '/images/vue.png'
  },
  {
    id: 2,
title: 'Асинхронное программирование на JavaScript: объяснение',
summary: 'Разберитесь с Promise, async/await, event loop и очередью микрозадач в одной статье.',
    date: '2024-05-08',
    category: 'JavaScript',
    cover: '/images/js.png'
  },
  {
    id: 3,
title: 'CSS Grid Layout на практике',
summary: 'Легко реализовать сложные адаптивные макеты с помощью CSS Grid.',
    date: '2024-05-05',
    category: 'CSS',
    cover: '/images/css.png'
  }
])
</script>

<template>
  <div class="home">
    <h2 class="section-title">Последние статьи</h2>

    <!-- Загрузка -->
    <p v-if="!articles.length" class="empty-tip">Статей пока нет, следите за обновлениями.</p>

    <!-- Список карточек статей -->
    <div v-else class="article-grid">
      <div
       v-for="article in articles"
       :key="article.id"
       class="article-card"
     >
        <img :src="article.cover" :alt="article.title" class="card-cover">
        <div class="card-content">
          <span class="card-category">{{ article.category }}</span>
          <h3 class="card-title">{{ article.title }}</h3>
          <p class="card-summary">{{ article.summary }}</p>
          <span class="card-date">{{ article.date }}</span>
        </div>
      </div>
    </div>
  </div>
</template>

<style scoped>
.home {
  max-width: 960px;
  margin: 0 auto;
  padding: 20px;
}

.section-title {
  font-size: 24px;
  margin-bottom: 20px;
  color: #333;
}

.article-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 24px;
}

.article-card {
  background: #fff;
  border-radius: 12px;
  overflow: hidden;
  box-shadow: 0 2px 12px rgba(0,0,0,0.08);
  transition: transform 0.2s, box-shadow 0.2s;
  cursor: pointer;
}

.article-card:hover {
  transform: translateY(-4px);
  box-shadow: 0 8px 24px rgba(0,0,0,0.12);
}

.card-cover {
  width: 100%;
  height: 180px;
  object-fit: cover;
}

.card-content {
  padding: 16px;
}

.card-category {
  display: inline-block;
  padding: 2px 10px;
  background: #E8EEF5;
  color: #427DB8;
  border-radius: 12px;
  font-size: 12px;
  margin-bottom: 8px;
}

.card-title {
  font-size: 18px;
  margin-bottom: 8px;
  color: #222;
}

.card-summary {
  font-size: 14px;
  color: #666;
  line-height: 1.6;
  margin-bottom: 12px;
}

.card-date {
  font-size: 12px;
  color: #999;
}

.empty-tip {
  text-align: center;
  color: #999;
  padding: 60px 0;
  font-size: 16px;
}
</style>

Краткое содержание главы

В этой главе вы изучили четыре основные возможности синтаксиса шаблонов:{{ }}интерполяция для отображения данных,v-bind(сокращённая запись:) для привязки атрибутов,v-forциклы для рендеринга списков,v-if/v-elseусловия для управления видимостью.

На данный момент главная страница блога уже может динамически отображать карточки статей на основе данных JS.

Другие расширения