模板语法渲染
本章你将学会用 Vue 的模板语法把 JS 数据渲染成 HTML,让博客首页展示文章卡片列表。
插值表达式 {{ }}
插值表达式是 Vue 中最基础的数据绑定方式。
它把 JS 变量的值「插入」到 HTML 中,语法是双层花括号包裹变量名。
实例
const blogTitle = 'RUNOOB 前端笔记'
const author = '小明'
</script>
<template>
<h1>{{ blogTitle }}</h1>
<p>作者:{{ author }}</p>
<p>当前时间:{{ new Date().toLocaleDateString() }}</p>
</template>
页面会渲染出:
RUNOOB 前端笔记 作者:小明 当前时间:2024/5/15
花括号里可以放任何 JS 表达式:变量、运算、三元表达式、函数调用都行,但不能放语句(如 if、for)。
插值表达式只替换标签内部的文本,不会替换标签。比如
中的{{ content }}标签本身不受影响。
属性绑定 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:属性名="变量" -->
<img v-bind:src="coverUrl" v-bind:alt="文章封面">
<!-- 简写:直接用 :属性名="变量" -->
<a :href="linkUrl">阅读全文</a>
<!-- 动态 class:用对象语法 -->
<div :class="{ active: isActive, 'text-bold': true }">
这段文字有 active 和 text-bold 两个 class
</div>
</template>
简写冒号 是最常见的写法,实际开发中几乎不会用
v-bind:全称。
列表渲染 v-for
博客首页需要展示多篇文章,一篇文章就是一个对象,多篇文章就是一个对象数组。
v-for 可以循环数组,为每个元素生成对应的 HTML。
实例
<script setup>
// 用 JS 对象数组模拟文章数据(后续会改成从 JSON 文件加载)
const articles = [
{
id: 1,
title: 'Vue3 入门完全指南',
summary: '从零开始学习 Vue3 组合式 API,涵盖 ref、reactive、computed 等核心概念。',
date: '2024-05-10',
category: 'Vue',
cover: '/images/vue.png'
},
{
id: 2,
title: 'JavaScript 异步编程详解',
summary: '一文搞懂 Promise、async/await、事件循环与微任务队列。',
date: '2024-05-08',
category: 'JavaScript',
cover: '/images/js.png'
},
{
id: 3,
title: 'CSS Grid 布局实战',
summary: '用 CSS Grid 轻松实现复杂的响应式布局,告别 float 和 flexbox 的局限。',
date: '2024-05-05',
category: 'CSS',
cover: '/images/css.png'
}
]
</script>
<template>
<div class="article-list">
<!-- v-for="每一项 in 数组" :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: #e8f5e9;
color: #42b883;
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(推荐) 正确追踪每个元素,高效更新 数组下标 index 插入/删除时可能造成状态错乱(如输入框内容对调) 不写 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 组合式 API,涵盖 ref、reactive、computed 等核心概念。',
date: '2024-05-10',
category: 'Vue',
cover: '/images/vue.png'
},
{
id: 2,
title: 'JavaScript 异步编程详解',
summary: '一文搞懂 Promise、async/await、事件循环与微任务队列。',
date: '2024-05-08',
category: 'JavaScript',
cover: '/images/js.png'
},
{
id: 3,
title: 'CSS Grid 布局实战',
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: #e8f5e9;
color: #42b883;
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 数据动态渲染文章卡片了。
