现在位置: 首页 > Vue3 教程 > 正文

模板语法渲染

本章你将学会用 Vue 的模板语法把 JS 数据渲染成 HTML,让博客首页展示文章卡片列表。


插值表达式 {{ }}

插值表达式是 Vue 中最基础的数据绑定方式。

它把 JS 变量的值「插入」到 HTML 中,语法是双层花括号包裹变量名。

实例

<script setup>
const blogTitle = 'RUNOOB 前端笔记'
const author = '小明'
</script>

<template>
  <h1>{{ blogTitle }}</h1>
  <p>作者:{{ author }}</p>
  <p>当前时间:{{ new Date().toLocaleDateString() }}</p>
</template>

页面会渲染出:

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

花括号里可以放任何 JS 表达式:变量、运算、三元表达式、函数调用都行,但不能放语句(如 iffor)。

插值表达式只替换标签内部的文本,不会替换标签。比如

{{ 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 数据动态渲染文章卡片了。