Vue.js: 模板语法
最后更新:2026-10-20
Vue 的模板语法是声明式的 HTML 扩展——在普通 HTML 之上加了一些"指令"和"插值",让你能把数据渲染到 DOM 上。整个模板语法和 HTML 90% 相似,学过 HTML 的人 30 分钟就能上手。
Vue 模板的核心是 3 个动作:插值(显示数据)+ 指令(绑定属性/事件)+ 表达式(运行 JS)。本课带你掌握这 3 个动作的标准写法。
1. 你将学到
- Mustache 插值
{{ }}的 4 种用法 - v-text、v-html、v-once 3 个文本指令的区别
- v-bind 属性绑定的缩写
:和对象语法 - v-on 事件绑定的缩写
@和修饰符 - 模板中可用的 JS 表达式限制(不能写语句)
- v-pre、v-cloak 2 个边界指令的用途
2. 一个电商商品卡片的渲染需求
(1) 痛点:30 个商品,复制粘贴 30 次?
Alice 正在构建一个电商后台。她需要展示 30 个商品卡片。最初的做法:
HTML
<!-- 复制粘贴 30 次,噩梦... -->
<div class="product-card">
<h3>iPhone 15 Pro</h3>
<p>Price: $999</p>
<button>Edit</button>
</div>
<div class="product-card">
<h3>MacBook Pro</h3>
<p>Price: $2499</p>
<button>Edit</button>
</div>
<!-- ... 还有 28 个 ... -->
产品经理 Charlie 说"把价格格式改成带货币符号":
"Alice,你不可能手动改 30 个文件。下个月要是 5,000 个商品呢?我们需要动态模板。"
(2) Vue 模板解法:1 个组件,30 个数据
5 行模板代码 × 30 个商品 = 0 复制粘贴。当产品名/价格变化时,Vue 自动更新 DOM。
(3) 收益
使用 Vue 模板后:
- 代码量:30 × 15 行 = 450 行 → 1 个模板 + 30 条数据 = 60 行(-87%)
- 维护成本:改 1 个模板样式 → 30 个商品同步更新
- 新增商品:加 1 行数据 → 模板自动渲染
3. 插值:Mustache {{ }}
(1) 4 种插值写法
| 写法 | 效果 | 示例 |
|---|---|---|
{{ var }} |
显示变量值 | <p>{{ username }}</p> → Alice |
{{ expr }} |
显示 JS 表达式结果 | <p>{{ count + 1 }}</p> → 6 |
{{ fn() }} |
调用函数返回值 | <p>{{ formatDate(date) }}</p> → 2026-07-02 |
{{ obj.prop }} |
访问对象属性 | <p>{{ user.name }}</p> → Alice |
(2) 插值 5 大特性
(3) 插值 vs v-text 区别
▶ 示例:多种插值写法
▶ 试一试输出:
TEXT
变量: Alice
表达式: 11
Passed (≥60) ← score=75,只渲染这一行,Failed 行不出现
日期: 2026-10-18 ← 按运行当天日期输出 YYYY-MM-DD
用户: Alice
(4) 📊 模板 vs HTML 速查
| 元素 | HTML 写法 | Vue 写法 | 说明 |
|---|---|---|---|
| 静态文本 | <p>Hello</p> |
<p>{{ msg }}</p> |
改动态 |
| 静态属性 | <img src="x.jpg"> |
<img :src="url"> |
改动态 |
| 静态 class | <div class="box"> |
<div :class="cls"> |
改动态 |
| 静态 style | <div style="color: red"> |
<div :style="sty"> |
改动态 |
| 点击事件 | <button onclick="fn()"> |
<button @click="fn"> |
改 Vue |
| 条件渲染 | 无 | <div v-if="ok"> |
Vue 独有 |
| 列表渲染 | 无 | <div v-for="i in list"> |
Vue 独有 |
4. 文本指令:v-text / v-html / v-once
(1) 三指令对比
| 指令 | 作用 | 场景 | 安全性 |
|---|---|---|---|
{{ }} 插值 |
文本插值 | 默认首选 | ✅ 安全 |
v-text |
设置元素 textContent | 替代插值的指令写法 | ✅ 安全 |
v-html |
设置元素 innerHTML | 渲染富文本(慎用) | ⚠️ XSS 风险 |
v-once |
只渲染一次,后续不更新 | 静态优化 | ✅ 安全 |
(2) v-html 警告
(3) v-once 性能优化
5. 属性绑定:v-bind 与缩写 :
(1) v-bind 基础
(2) class 与 style 绑定(重点)
(3) style 绑定
▶ 示例:5 种 v-bind 写法
▶ 试一试输出:
TEXT
1. 基础: [50px 占位图]
2. 动态属性: [50px 占位图] ← 同一张图,动态属性名为 alt,值为 Logo
3. 对象语法: A ← span 带 class="active"
4. 数组语法: B ← span 带 class="active error"
5. 字符串拼接: Profile ← 链接指向 https://example.com/users/1001
6. 事件绑定:v-on 与缩写 @
(1) v-on 基础
(2) 常用事件修饰符(9 个)
(3) 修饰符链
▶ 示例:5 种 v-on 写法
▶ 试一试输出:
TEXT
1. Click ← 点击后控制台打印 clicked
2. + (count: 0) ← 每点一次数字 +1:count: 1 → count: 2
3. Delete Item A ← 点击后控制台打印 delete 1 PointerEvent
4. Save (阻止冒泡+默认行为) ← 点击后控制台打印 Save 按钮被点击
5. [Ctrl+Enter 提交 输入框] ← 输入内容后按 Ctrl+Enter 打印 Ctrl+Enter 提交
7. 表达式限制(不能写语句)
(1) 模板表达式 vs JS 语句
(2) 表达式 vs 计算属性
| 场景 | 用表达式 | 用计算属性 |
|---|---|---|
| 简单计算(1-2 个运算符) | ✅ | ❌ |
| 复杂逻辑(多步、循环) | ❌ | ✅ |
| 需要缓存 | ❌ | ✅ |
| 需要传参数 | ✅ | ❌(用方法代替) |
8. 边界指令:v-pre / v-cloak
(1) v-pre:跳过编译
场景:展示 Vue 模板语法本身(如教学、文档站)。
(2) v-cloak:编译前隐藏
场景:防止编译前用户看到 {{ message }} 闪烁。
9. 完整示例:动态商品卡片
▶ 示例:基础商品卡片
▶ 试一试输出:
TEXT
iPhone 15 Pro
$999
Only 5 left ← 徽章带 low-stock 类(黄色)
[Add to Cart] ← 点击后控制台打印 Added iPhone 15 Pro,页面文本不变
10. 常见错误速查
前面 8 章讲完了插值、v-text/v-html、v-bind、v-on 和表达式限制。最后把这几个最容易踩的坑集中列出来,写模板遇到问题就回来对照。
(1) 📊 5 个常见错误
| 错误 | 现象 | 解决 |
|---|---|---|
忘记 .value |
模板里写 {{ count }},JS 里写 count.value |
模板自动解包,JS 需 .value |
写 if/for 在 {{ }} |
编译报错 | 用 v-if / v-for 指令 |
| v-html XSS | 用户输入 <script> 执行 |
用 DOMPurify 清理 |
| 内联函数未传 $event | 拿不到 event 对象 | @click="fn($event)" 显式传 |
| 修饰符顺序错 | 阻止冒泡失败 | .stop 写在 .prevent 前(按需) |
❓ 常见问题
Q
{{ }} 和 v-text 有什么区别?A 效果一样,都是设置元素的 textContent。区别是
{{ }} 可以和静态文本混用(<p>Hi, {{ name }}</p>),v-text 必须独占整个元素(<p v-text="msg"></p>)。推荐用 {{ }},更灵活。Q v-html 安全吗?
A 不安全。v-html 会把字符串作为 HTML 解析,恶意用户可以注入
<script> 攻击你的站点。除非你 100% 信任数据源(如自己写的 Markdown 渲染),否则用 {{ }} 插值或先 DOMPurify.sanitize() 清理。Q v-on 修饰符链的执行顺序?
A 从左到右。例如
@click.stop.prevent 先 stopPropagation() 再 preventDefault()。Q v-bind 可以缩写,v-on 也能吗?
A v-bind 缩写是
:(去掉 v-bind),v-on 缩写是 @(推荐用)。两个缩写都是 Vue 2 起就支持的官方写法,IDE 高亮和自动补全都支持。Q 模板里能写 if/else 吗?
A 不能。模板表达式要求有返回值,if/for 是语句不是表达式。用 v-if / v-else-if / v-else 指令实现条件渲染。
Q v-bind 怎么动态切换多个 class?
A 用对象语法
:class="{ active: isActive, 'text-danger': hasError }"。或数组语法 :class="[activeClass, errorClass]"。两种可以混用::class="[isActive && 'active', { 'error': hasError }]"。Q 怎么监听键盘 Ctrl+S?
A 用系统修饰符
@keyup.ctrl.s="save" 或 @keydown.ctrl.s.prevent="save"(加 .prevent 阻止浏览器默认保存对话框)。Vue 3 还支持精确修饰符 .exact,如 @click.ctrl.exact 要求只按 Ctrl 不能加其他键。📖 小节
- Vue 模板语法是声明式 HTML 扩展,核心是插值 + 指令 + 表达式
- Mustache 插值
{{ }}支持变量、表达式、函数调用、三元运算 - 模板表达式不能写 if/for/变量声明(用 v-if / v-for 指令)
- v-text 替换整个元素文本,v-html 渲染富文本(XSS 风险)
- v-once 性能优化(静态内容只渲染一次),v-pre 跳过编译
- v-bind 缩写
:,v-on 缩写@,3 个常用 class 绑定方式 - 9 个事件修饰符:.stop / .prevent / .once / .self / .capture / .passive + 键盘/鼠标/系统
- 模板表达式 vs 计算属性的选择:简单用表达式,复杂用 computed
📝 作业
-
基础题(难度⭐) 写一个 Vue 3 组件,渲染一个用户卡片,包含:
- 用户名(插值)
- 头像(v-bind)
- "Follow" 按钮(v-on)
- 在线/离线状态(class 动态切换)
数据用:用户对象
{ name: 'Alice', avatar: 'alice.jpg', online: true } -
进阶题(难度⭐⭐) 实现一个简单的 Todo 列表:
- 输入框(v-model 暂不用,v-bind:value + @input 模拟)
- 添加按钮(@click + 表达式)
- 列表渲染(v-for,下一课学)
- 每项有删除按钮(@click + 传参)
数据:
const todos = ref(['Learn Vue', 'Build app', 'Deploy']) -
挑战题(难度⭐⭐⭐) 写一个完整的商品详情卡片组件,支持:
- 5 种商品状态徽章(在售/缺货/预售/促销/下架)
- 5 种状态对应不同 class 颜色(用对象语法批量绑定)
- 数量加减按钮(@click 累加/累减)
- 数量 ≥ 库存时禁用"加入购物车"按钮(:disabled 动态)
- 至少 3 个事件修饰符(@click.stop / @submit.prevent 等)