Рендеринг синтаксиса шаблонов
В этой главе вы научитесь использовать синтаксис шаблонов Vue для отрисовки данных JS в HTML, чтобы главная страница блога отображала список карточек статей.
Интерполяционное выражение {{ }}
Интерполяционное выражение — самый базовый способ привязки данных в Vue.
Оно «вставляет» значение переменной JS в HTML. Синтаксис — двойные фигурные скобки, окружающие имя переменной.
Пример
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)。
Интерполяционное выражение заменяет только текст внутри тега, а не сам тег. Например,
in{{ content }}сам тег не затрагивается.
Привязка атрибутов v-bind (сокращённо :)
Интерполяционные выражения можно использовать только для содержимого тега, а не для HTML-атрибутов.
Чтобы использовать JS-переменные в атрибутах, нужно использовать директивуv-bind.
Пример
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 для каждого элемента.
Пример
// Использовать массив 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.
Пример
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 — для стабильных условий.
Практика: Готовая главная страница блога
Объедините синтаксис шаблонов, изученный ранее, и напишите полноценный компонент главной страницы блога.
Пример
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.
Другие расширения