Vue.js 的模板语法是构建用户界面的核心,它基于 HTML 扩展,提供了声明式的方式将数据与 DOM 绑定。模板语法主要分为插值语法和指令语法两大类,结合双向数据绑定和事件处理机制,能够高效实现动态界面开发。本章将系统讲解模板语法的核心特性及实际应用,每个知识点均配套完整案例,帮助开发者快速掌握数据驱动视图的实现方式。
插值语法是 Vue 模板中最基础的数据绑定方式,通过双大括号 {{ }} 包裹 JavaScript 表达式,实现数据到视图的动态渲染。其核心功能是解析标签体内容,将表达式结果插入到 DOM 中[13]。
基本用法
插值表达式支持多种 JavaScript 表达式类型,包括变量访问、属性读取、函数调用、运算及三元表达式等:
<div>
<p>{{ nickname.toUpperCase() }}</p> <!-- 方法调用:将昵称转为大写 -->
<p>{{ age >= 18 ? '成年' : '未成年' }}</p> <!-- 三元表达式:条件判断 -->
<p>{{ user.name + '(' + user.age + ')' }}</p> <!-- 字符串拼接 -->
<p>{{ getGreeting() }}</p> <!-- 函数调用:执行方法返回结果 -->
</div>
const app = Vue.createApp({
data() {
return {
nickname: 'vue-dev',
age: 22,
user: { name: '张三', age: 28 },
getGreeting: () => 'Hello Vue!'
}
}
}).mount('#app');
关键限制
插值语法虽灵活,但存在以下使用限制,需特别注意:
插值表达式使用规范
age + 1,但不能写 if (age > 18) { ... } 或 for 循环。 src="{{ imageUrl }}")中使用,需通过 v-bind 指令实现属性绑定。 data 或 setup 中声明,否则会报错(如 {{ hobby }} 若未定义则抛出引用错误)[14]。命令式 vs 声明式:渲染逻辑对比
传统命令式编程需手动操作 DOM 实现数据渲染,而 Vue 的声明式语法可大幅简化流程。以渲染用户列表为例:
| 编程范式 | 实现代码 | 核心差异 |
|---|---|---|
| 命令式 | javascript let persons = [ {id:1,name:'张三',age:18}, {id:2,name:'李四',age:20} ]; let _str = ''; persons.forEach(i => { _str += `<li>${i.id}-${i.name}-${i.age}</li>` }); document.querySelector('#list').innerHTML = _str; |
需手动拼接 HTML 字符串、操作 DOM,逻辑与 DOM 操作耦合 |
| 声明式 | html <ul id="list"> <li v-for="i in persons" :key="i.id"> {{i.id}}-{{i.name}}-{{i.age}} </li> </ul> javascript const app = Vue.createApp({ data() { return { persons: [ {id:1,name:'张三',age:18}, {id:2,name:'李四',age:20} ] } } }).mount('#list'); |
直接描述目标结果,Vue 自动处理 DOM 更新,逻辑与视图分离[8] |
指令是 Vue 模板的核心功能,以 v- 为前缀,用于声明式地控制 DOM 行为(如属性绑定、事件监听、条件渲染、列表循环等)。指令的值需为 JavaScript 表达式,且可直接访问实例中的数据[14]。
功能:将标签属性与数据动态关联,数据变化时自动更新属性值。
语法:v-bind:属性名="表达式",简写为 :属性名="表达式"。
应用场景:动态加载图片、设置链接、绑定样式等。
案例:动态图片加载
根据数据切换显示不同图片:
<div id="app">
<img
:src="currentImage"
:alt="imageDesc"
:title="imageTitle"
style="width: 200px;"
>
<button @click="switchImage">切换图片</button>
</div>
const app = Vue.createApp({
data() {
return {
// 图片列表
images: [
{ src: 'https://picsum.photos/id/237/200/200', desc: '小狗', title: '可爱宠物' },
{ src: 'https://picsum.photos/id/1/200/200', desc: '风景', title: '自然景观' }
],
currentIndex: 0 // 当前显示图片索引
}
},
computed: {
currentImage() { return this.images[this.currentIndex].src; },
imageDesc() { return this.images[this.currentIndex].desc; },
imageTitle() { return this.images[this.currentIndex].title; }
},
methods: {
switchImage() {
this.currentIndex = (this.currentIndex + 1) % this.images.length;
}
}
}).mount('#app');
Vue 3.4+ 增强特性:支持同名速记语法,当属性名与数据名相同时,可简化为 :属性名。例如 <img :id :src :alt> 等价于 <img :id="id" :src="src" :alt="alt">[15]。
功能:绑定 DOM 事件到方法,用户触发事件时执行指定逻辑。
语法:v-on:事件名="方法名/表达式",简写为 @事件名="方法名/表达式"。
应用场景:按钮点击、表单提交、键盘输入等交互。
案例:计数器组件
实现点击按钮增减数字的计数器:
<div id="counter">
<h3>当前计数:{{ count }}</h3>
<button @click="increment">+1</button> <!-- 调用方法增加计数 -->
<button @click="count--">-1</button> <!-- 直接执行表达式减少计数 -->
<button @click="add(5)">+5</button> <!-- 传递参数 -->
</div>
const app = Vue.createApp({
data() { return { count: 0 }; },
methods: {
increment() { this.count++; }, // 增加1
add(step) { this.count += step; } // 增加指定步长
}
}).mount('#counter');
功能:根据条件动态添加/移除 DOM 元素(而非隐藏),实现条件显示。
语法:v-if="条件"、v-else-if="条件"、v-else(需紧跟 v-if 元素)。
应用场景:用户角色权限展示、登录状态切换、空数据提示等。
案例:用户角色权限控制
根据用户角色(管理员/普通用户)显示不同操作按钮:
<div id="user-role">
<div v-if="user.role === 'admin'">
<h3>管理员面板</h3>
<button>用户管理</button>
<button>系统设置</button>
</div>
<div v-else-if="user.role === 'editor'">
<h3>编辑面板</h3>
<button>内容发布</button>
</div>
<div v-else>
<h3>访客视图</h3>
<p>请登录后操作</p>
</div>
</div>
const app = Vue.createApp({
data() {
return {
user: { role: 'admin' } // 可修改为 'editor' 或其他值测试效果
}
}
}).mount('#user-role');
功能:基于数组或对象循环生成 DOM 列表。
语法:v-for="(item, index) in 数组" :key="唯一标识",index 为可选参数(索引)。
核心要求:必须绑定 :key 属性,值需为唯一不变的标识(如 ID),用于 Vue 高效更新 DOM[16]。
案例:用户列表渲染
循环展示用户信息,并支持删除操作:
<div id="user-list">
<ul>
<!-- v-for遍历users数组,:key绑定唯一ID确保高效更新 -->
<li v-for="(user, index) in users" :key="user.id" style="margin: 8px 0;">
{{ index + 1 }}. {{ user.name }} ({{ user.age }}岁)
<button @click="deleteUser(user.id)">删除</button>
</li>
</ul>
<p v-if="users.length === 0">暂无用户数据</p>
</div>
const app = Vue.createApp({
data() {
return {
users: [
{ id: 1, name: '张三', age: 25 },
{ id: 2, name: '李四', age: 30 },
{ id: 3, name: '王五', age: 28 }
]
}
},
methods: {
deleteUser(id) {
this.users = this.users.filter(user => user.id !== id);
}
}
}).mount('#user-list');
为什么需要 :key?
若不指定 :key,Vue 会使用“就地更新”策略,可能导致列表项状态(如输入框内容)错乱。key 确保每个节点与数据唯一对应,避免重复渲染问题[16]。
功能:在表单元素上实现数据与视图的双向同步——数据变化更新视图,用户输入更新数据。
原理:语法糖,等价于 v-bind:value="数据" + v-on:input="数据 = $event.target.value"[13]。
支持元素:input(文本/复选/单选)、textarea、select 等表单控件。
1. 文本框/文本域
绑定字符串类型数据:
<div id="app">
<input type="text" v-model="username" placeholder="输入用户名">
<p>用户名:{{ username }}</p>
<textarea v-model="description" rows="3" placeholder="输入描述"></textarea>
<p>描述:{{ description }}</p>
</div>
const app = Vue.createApp({
data() {
return { username: '', description: '' };
}
}).mount('#app');
2. 复选框
value)。<div id="checkboxes">
<!-- 单个复选框:布尔值绑定 -->
<label>
<input type="checkbox" v-model="agree"> 同意协议
</label>
<p>是否同意:{{ agree ? '是' : '否' }}</p>
<!-- 多个复选框:数组绑定 -->
<div>
<p>选择爱好(可多选):</p>
<label><input type="checkbox" v-model="hobbies" value="reading"> 阅读</label>
<label><input type="checkbox" v-model="hobbies" value="sports"> 运动</label>
<label><input type="checkbox" v-model="hobbies" value="coding"> 编程</label>
</div>
<p>选中的爱好:{{ hobbies.join(', ') }}</p>
</div>
const app = Vue.createApp({
data() {
return { agree: false, hobbies: [] };
}
}).mount('#checkboxes');
3. 下拉框
value。 multiple):绑定数组。<div id="selects">
<!-- 单选下拉框 -->
<select v-model="city">
<option value="">请选择城市</option>
<option value="beijing">北京</option>
<option value="shanghai">上海</option>
</select>
<p>选中城市:{{ city }}</p>
<!-- 多选下拉框(按住Ctrl键多选) -->
<select v-model="tags" multiple size="3">
<option value="vue">Vue</option>
<option value="react">React</option>
<option value="angular">Angular</option>
</select>
<p>选中标签:{{ tags.join(', ') }}</p>
</div>
const app = Vue.createApp({
data() {
return { city: '', tags: [] };
}
}).mount('#selects');
单向绑定 vs 双向绑定
| 绑定方式 | 语法 | 数据流向 | 应用场景 |
|---|---|---|---|
| 单向绑定(v-bind) | :value="data" |
仅从 data → 视图 |
非表单元素(如图片、div)、无需用户输入的场景 |
| 双向绑定(v-model) | v-model="data" |
data ↔ 视图 |
表单元素(输入框、复选框等),需同步用户输入的场景 |
事件修饰符是 v-on 的增强功能,通过 .修饰符 语法简化常见事件处理逻辑(如阻止默认行为、停止冒泡等),无需手动编写复杂代码。
| 修饰符 | 作用 | 应用场景 |
|---|---|---|
.prevent |
阻止事件默认行为 | 阻止表单提交、链接跳转 |
.终止 |
停止事件冒泡 | 嵌套元素点击事件隔离 |
.once |
事件仅触发一次 | 一次性按钮(如“同意协议”) |
.self |
仅元素自身触发时执行 | 忽略子元素冒泡的事件 |
案例 1:阻止表单默认提交
表单提交时默认会刷新页面,使用 .prevent 阻止:
<form @submit.prevent="handleSubmit">
<input type="text" v-model="username" required>
<button type="submit">提交</button>
</form>
methods: {
handleSubmit() {
console.log('提交数据:', this.username); // 无需手动调用 event.preventDefault()
}
}
案例 2:停止事件冒泡
内层元素点击时,避免触发外层元素的点击事件:
<div @click="parentClick" style="padding: 20px; background: #eee;">
外层div
<button @click.终止="childClick">点击我(仅触发子事件)</button>
</div>
methods: {
parentClick() { console.log('触发外层点击'); },
childClick() { console.log('触发按钮点击'); } // 不会触发 parentClick
}
通过事件修饰符,可大幅减少模板中对原生事件对象(event)的直接操作,使代码更简洁、可读性更强。
模板语法是 Vue 框架的核心竞争力之一,通过插值语法实现数据到视图的声明式渲染,指令系统控制 DOM 行为,双向绑定简化表单交互,事件修饰符优化事件处理。掌握这些语法不仅能提升开发效率,更能深刻理解 Vue “数据驱动视图”的设计思想。实际开发中,需注意 :key 的唯一性、插值表达式的使用限制、事件修饰符的合理搭配,以构建高效、可维护的 Vue 应用。