Renderizado de sintaxis de plantillas
En este capítulo aprenderás a usar la sintaxis de plantillas de Vue para renderizar datos de JS como HTML, haciendo que la página de inicio del blog muestre una lista de tarjetas de artículos.
Expresión de interpolación {{ }}
La expresión de interpolación es la forma más básica de enlace de datos en Vue.
Inserta el valor de una variable JS «en» el HTML; la sintaxis consiste en envolver el nombre de la variable entre llaves dobles.
Ejemplo
const blogTitle = 'EJEMPLO Notas de frontend'
const author = 'Xiaoming'
</script>
<template>
<h1>{{ blogTitle }}</h1>
<p>Autor: {{ author }}</p>
<p>Hora actual: {{ new Date().toLocaleDateString() }}</p>
</template>
La página mostrará:
EJEMPLO 前端笔记 作者:小明 当前时间:2024/5/15
Dentro de las llaves se puede poner cualquier expresión de JS: variables, operaciones, expresiones ternarias, llamadas a funciones; pero no se pueden poner sentencias (comoif、for)。
La expresión de interpolación solo reemplaza el texto dentro de la etiqueta, no reemplaza la etiqueta. Por ejemplo
en{{ content }}la etiqueta en sí no se ve afectada.
Enlace de atributos v-bind (abreviatura :)
La expresión de interpolación solo se puede usar en el contenido de la etiqueta, no en atributos HTML.
Para usar variables de JS en un atributo, debes usarv-bindla directiva.
Ejemplo
const coverUrl = '/images/vue-cover.png'
const linkUrl = '/post/1'
const isActive = true
</script>
<template>
<!-- Escritura completa: v-bind:nombreDeAtributo="variable" -->
<img v-bind:src="coverUrl" v-bind:alt="Portada del artículo">
<!-- Abreviatura: usa directamente :nombreDeAtributo="variable" -->
<a :href="linkUrl">Leer artículo completo</a>
<!-- class dinámica: con sintaxis de objeto -->
<div :class="{ active: isActive, 'text-bold': true }">
Este texto tiene dos clases: active y text-bold
</div>
</template>
La abreviatura con dos puntoses la forma más común de escribirla; en el desarrollo real casi nunca se usav-bind:el nombre completo.
Renderizado de listas v-for
La página de inicio del blog necesita mostrar varios artículos; un artículo es un objeto, y varios artículos son un array de objetos.
v-forSe puede recorrer el array y generar el HTML correspondiente para cada elemento.
Ejemplo
// Simulamos los datos de los artículos con un array de objetos JS (más adelante se cambiará para cargarlos desde un archivo JSON)
const articles = [
{
id: 1,
title: 'Guía completa para empezar con Vue3',
summary: 'Aprende desde cero la Composition API de Vue3, incluyendo conceptos clave como ref, reactive y computed.',
date: '2024-05-10',
category: 'Vue',
cover: '/images/vue.png'
},
{
id: 2,
title: 'Explicación detallada de la programación asíncrona en JavaScript',
summary: 'Entiende de una vez Promise, async/await, el bucle de eventos y la cola de microtareas.',
date: '2024-05-08',
category: 'JavaScript',
cover: '/images/js.png'
},
{
id: 3,
title: 'Práctica de diseño con CSS Grid',
summary: 'Implementa fácilmente diseños responsive complejos con CSS Grid, dejando atrás las limitaciones de float y flexbox.',
date: '2024-05-05',
category: 'CSS',
cover: '/images/css.png'
}
]
</script>
<template>
<div class="article-list">
<!-- v-for="cadaElemento in array" :key="identificadorUnico" -->
<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>
La importancia del atributo key
:keyes el compañero imprescindible de v-for; le indica a Vue la identidad de cada elemento.
Cuando el orden del array cambia (como al insertar, eliminar u ordenar), Vue usa key para determinar qué elementos del DOM necesitan actualizarse y cuáles se pueden reutilizar.
| Valores de key | Consecuencias |
|---|---|
| id único (recomendado) | Sigue correctamente cada elemento y actualiza de manera eficiente |
| índice del array (index) | Al insertar o eliminar puede causar errores de estado (por ejemplo, el contenido de los campos de entrada se intercambia) |
| Sin escribir key | La consola mostrará una advertencia; Vue usa por defecto la estrategia de «actualización in situ», con un rendimiento peor |
Añade siempre a v-for una key única y estable; no uses index como key. Es uno de los hábitos más importantes en el desarrollo con Vue.
Renderizado condicional v-if / v-else
Cuando necesitas mostrar contenido diferente según distintas condiciones, usav-ifla familia de directivas.
Ejemplo
import { ref } from 'vue'
const articles = ref([]) // Lista de artículos (un array vacío indica que no hay datos por ahora)
const isLoading = ref(true) // Estado de carga
// Simula la carga de datos: completa los datos después de 2 segundos
setTimeout(() => {
articles.value = [
{ id: 1, title: 'Introducción a Vue3', summary: '...' },
{ id: 2, title: 'Comparación con React', summary: '...' }
]
isLoading.value = false
}, 2000)
</script>
<template>
<div>
<!-- Cargando -->
<p v-if="isLoading">Cargando, por favor espera...</p>
<!-- Muestra la lista cuando hay datos -->
<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>
<!-- Muestra el estado vacío cuando no hay datos -->
<p v-else>Aún no hay artículos, permanece atento.</p>
</div>
</template>
Este patrón cubre los tres estados más comunes de la interfaz de usuario:Cargando → Con datos → Sin datos。
v-if vs v-show
| Directiva | Método de conmutación | Coste de renderizado inicial | Coste de conmutación | Casos de uso |
|---|---|---|---|---|
| v-if | Añade/elimina nodos del DOM | Bajo (no renderiza) | Alto (reconstruye el DOM) | Escenarios donde la condición cambia poco, como el control de permisos |
| v-show | Conmuta el display de CSS | Alto (siempre renderiza) | Bajo (solo cambia el estilo) | Escenarios de conmutación frecuente, como el cambio de pestañas |
Regla sencilla: si se conmuta con frecuencia, usa v-show; si la condición es estable, usa v-if.
Manos a la obra: la página de inicio del blog completa
Integra toda la sintaxis de plantillas aprendida anteriormente y escribe un componente completo de la página de inicio del blog.
Ejemplo
import { ref } from 'vue'
// Datos de los artículos (por ahora están codificados; en capítulos posteriores se cambiarán para cargarlos con fetch)
const articles = ref([
{
id: 1,
title: 'Guía completa para empezar con Vue3',
summary: 'Aprende desde cero la Composition API de Vue3, incluyendo conceptos clave como ref, reactive y computed.',
date: '2024-05-10',
category: 'Vue',
cover: '/images/vue.png'
},
{
id: 2,
title: 'Explicación detallada de la programación asíncrona en JavaScript',
summary: 'Entiende de una vez Promise, async/await, el bucle de eventos y la cola de microtareas.',
date: '2024-05-08',
category: 'JavaScript',
cover: '/images/js.png'
},
{
id: 3,
title: 'Práctica de diseño con CSS Grid',
summary: 'Implementa fácilmente diseños responsive complejos con CSS Grid.',
date: '2024-05-05',
category: 'CSS',
cover: '/images/css.png'
}
])
</script>
<template>
<div class="home">
<h2 class="section-title">Artículos recientes</h2>
<!-- Cargando -->
<p v-if="!articles.length" class="empty-tip">Aún no hay artículos, permanece atento.</p>
<!-- Lista de tarjetas de artículos -->
<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>
Resumen del capítulo
En este capítulo has aprendido cuatro sintaxis de plantillas fundamentales:{{ }}interpolación para mostrar datos,v-bind(abreviatura:) para enlazar atributos,v-forrenderizado de listas en bucle,v-if/v-elsecontrol condicional de visibilidad.
A partir de aquí, la página de inicio del blog ya puede renderizar dinámicamente las tarjetas de artículos según los datos de JS.
Otras extensiones