Vue3 的模板语法是基于 HTML 的扩展,允许开发者声明式地将组件的数据绑定到 DOM 上。它结合了 HTML 的简洁性和 JavaScript 的动态能力,同时提供了一系列指令来处理常见的 DOM 操作场景。
一、文本插值
1. 基本文本绑定
使用双大括号 {{ }} 进行文本插值,将组件的数据实时显示在模板中:
<template>
<div>
<p>用户名:{{ username }}</p>
<p>年龄:{{ user.age }}</p>
<p>计算结果:{{ 1 + 2 * 3 }}</p>
<p>函数返回值:{{ formatDate(createTime) }}</p>
</div>
</template>
<script setup>
import { ref, reactive } from 'vue'
const username = ref('张三')
const user = reactive({ age: 25 })
const createTime = ref('2023-01-01')
function formatDate(date) {
return new Date(date).toLocaleString()
}
</script>
双大括号内可以是:
响应式变量(ref 或 reactive 对象的属性)
JavaScript 表达式(算术运算、三元运算等)
函数调用(返回值会被渲染)
注意:模板表达式只能是单个表达式,不能包含语句(如 if 语句、for 循环)或流程控制。
2. 原始 HTML 绑定
双大括号会将数据解释为普通文本,若需渲染 HTML 字符串,使用 v-html 指令:
<template>
<div>
<!-- 普通文本绑定(会显示标签) -->
<p>{{ rawHtml }}</p>
<!-- 渲染为 HTML -->
<p v-html="rawHtml"></p>
</div>
</template>
<script setup>
import { ref } from 'vue'
const rawHtml = ref('<strong style="color: red;">这是加粗的红色文本</strong>')
</script>
安全提示:动态渲染 HTML 存在 XSS 风险,避免将用户输入的内容直接通过 v-html 渲染,除非确认内容安全。
3. 一次性插值
使用 v-once 指令可以执行一次性插值,数据变化时,插值处的内容不会更新:
<template>
<div>
<p v-once>初始值:{{ count }}</p>
<p>实时值:{{ count }}</p>
<button @click="count++">增加</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
点击按钮后,v-once 所在的段落内容不会变化,而另一处会实时更新。
二、属性绑定
1. 基本属性绑定
使用 v-bind 指令绑定 HTML 属性到组件数据,缩写为 ::
<template>
<div>
<!-- 完整语法 -->
<img v-bind:src="imageUrl" alt="示例图片">
<!-- 缩写语法 -->
<img :src="imageUrl" :alt="imageAlt">
<!-- 绑定 class 属性 -->
<div :class="containerClass">容器</div>
<!-- 绑定 style 属性 -->
<p :style="textStyle">带样式的文本</p>
</div>
</template>
<script setup>
import { ref } from 'vue'
const imageUrl = ref('https://picsum.photos/200/300')
const imageAlt = ref('风景图片')
const containerClass = ref('main-container')
const textStyle = ref({
color: 'blue',
fontSize: '16px'
})
</script>
2. 动态属性名
可以使用方括号 [] 绑定动态属性名:
<template>
<div>
<!-- 属性名由 attributeName 动态决定 -->
<div :[attributeName]="value"></div>
<button @click="attributeName = 'title'">改为 title 属性</button>
<button @click="attributeName = 'data-id'">改为 data-id 属性</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
const attributeName = ref('title')
const value = ref('动态属性值')
</script>
3. Class 与 Style 绑定进阶
绑定 class 的多种方式:
<template>
<div>
<!-- 1. 字符串语法 -->
<div :class="basicClass">基础样式</div>
<!-- 2. 对象语法(控制是否应用类) -->
<div :class="{ active: isActive, 'text-danger': hasError }">
对象语法示例
</div>
<!-- 3. 数组语法(多个类名) -->
<div :class="[classA, classB]">数组语法示例</div>
<!-- 4. 数组+对象混合(条件应用类) -->
<div :class="[isActive ? activeClass : '', errorClass]">
混合语法示例
</div>
</div>
</template>
绑定 style 的多种方式:
<template>
<div>
<!-- 1. 对象语法 -->
<div :style="{ color: textColor, fontSize: fontSize + 'px' }">
样式对象示例
</div>
<!-- 2. 使用 reactive 对象 -->
<div :style="boxStyle">reactive 样式对象</div>
<!-- 3. 数组语法(多个样式对象) -->
<div :style="[baseStyle, specialStyle]">
样式数组示例
</div>
</div>
</template>
<script setup>
import { ref, reactive } from 'vue'
const textColor = ref('green')
const fontSize = ref(16)
const boxStyle = reactive({
width: '200px',
height: '100px',
backgroundColor: '#f0f0f0'
})
const baseStyle = ref({ margin: '10px', padding: '5px' })
const specialStyle = ref({ border: '1px solid #ccc' })
</script>
三、事件处理
1. 基本事件绑定
使用 v-on 指令绑定事件,缩写为 @:
<template>
<div>
<!-- 完整语法 -->
<button v-on:click="handleClick">点击我</button>
<!-- 缩写语法 -->
<button @click="handleClick">点击我</button>
<!-- 直接写表达式 -->
<button @click="count++">增加计数 ({{ count }})</button>
<!-- 绑定键盘事件 -->
<input @keyup="handleKeyUp" placeholder="按任意键">
</div>
</template>
<script setup>
import { ref } from 'vue'
const count = ref(0)
function handleClick() {
alert('按钮被点击了')
}
function handleKeyUp(event) {
console.log('按键:', event.key)
}
</script>
2. 事件修饰符
Vue 提供了事件修饰符,简化常见的事件处理逻辑:
| 修饰符 | 说明 |
|---|---|
.stop | 阻止事件冒泡 |
.prevent | 阻止默认行为(如表单提交) |
.capture | 使用事件捕获模式 |
.self | 仅当事件目标是元素本身时触发 |
.once | 事件仅触发一次 |
.passive | 优化触摸事件的滚动性能(不阻止默认行为) |
示例:
<template>
<div>
<!-- 阻止冒泡 -->
<div @click="parentClick">
父元素
<button @click.stop="childClick">子按钮</button>
</div>
<!-- 阻止默认行为(表单提交) -->
<form @submit.prevent="handleSubmit">
<button type="submit">提交(不刷新页面)</button>
</form>
<!-- 事件仅触发一次 -->
<button @click.once="handleOnceClick">只触发一次</button>
</div>
</template>
3. 按键修饰符
用于键盘事件,过滤特定按键:
<template>
<div>
<!-- 只有按 Enter 键才触发 -->
<input @keyup.enter="submitForm" placeholder="按回车提交">
<!-- 按 Esc 键清空输入 -->
<input @keyup.esc="clearInput" v-model="inputValue">
<!-- 系统修饰键(Ctrl、Alt、Shift、Meta) -->
<input @keyup.ctrl.67="copyContent" placeholder="Ctrl+C 复制">
</div>
</template>
<script setup>
import { ref } from 'vue'
const inputValue = ref('')
function submitForm() {
console.log('提交表单')
}
function clearInput() {
inputValue.value = ''
}
function copyContent() {
console.log('复制内容')
}
</script>
常见按键别名:.enter、.tab、.delete、.esc、.space、.up、.down、.left、.right。
四、表单输入绑定
1. 基本用法(v-model)
v-model 指令在表单元素上创建双向数据绑定,自动根据元素类型选择正确的绑定方式:
<template>
<form>
<!-- 文本输入框 -->
<div>
<label>用户名:</label>
<input type="text" v-model="username">
</div>
<!-- 多行文本框 -->
<div>
<label>简介:</label>
<textarea v-model="bio" rows="3"></textarea>
</div>
<!-- 复选框 -->
<div>
<label>
<input type="checkbox" v-model="isAgreed">
同意条款
</label>
</div>
<!-- 多个复选框(绑定数组) -->
<div>
<label>爱好:</label>
<label>
<input type="checkbox" v-model="hobbies" value="reading"> 阅读
</label>
<label>
<input type="checkbox" v-model="hobbies" value="sports"> 运动
</label>
</div>
<!-- 单选按钮组 -->
<div>
<label>性别:</label>
<label>
<input type="radio" v-model="gender" value="male"> 男
</label>
<label>
<input type="radio" v-model="gender" value="female"> 女
</label>
</div>
<!-- 下拉选择框 -->
<div>
<label>城市:</label>
<select v-model="city">
<option value="">请选择</option>
<option value="beijing">北京</option>
<option value="shanghai">上海</option>
</select>
</div>
</form>
</template>
<script setup>
import { ref } from 'vue'
const username = ref('')
const bio = ref('')
const isAgreed = ref(false)
const hobbies = ref([])
const gender = ref('')
const city = ref('')
</script>
2. v-model 修饰符
表单绑定的常用修饰符:
.lazy:默认实时同步,使用后在 change 事件触发时同步(如输入框失焦时)
.number:自动将输入值转为数字类型
.trim:自动过滤输入值的首尾空白字符
<template>
<div>
<input v-model.lazy="message" placeholder="失去焦点后同步">
<p>消息:{{ message }}</p>
<input v-model.number="age" type="text" placeholder="自动转为数字">
<p>年龄类型:{{ typeof age }}</p>
<input v-model.trim="username" placeholder="自动去除首尾空格">
<p>用户名长度:{{ username.length }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue'
const message = ref('')
const age = ref(0)
const username = ref('')
</script>
五、条件渲染
1. v-if / v-else-if / v-else
根据表达式的真假值条件渲染元素,会真正销毁和创建元素:
<template>
<div>
<button @click="score = Math.floor(Math.random() * 100)">
随机分数
</button>
<p>分数:{{ score }}</p>
<div v-if="score >= 90">优秀</div>
<div v-else-if="score >= 80">良好</div>
<div v-else-if="score >= 60">及格</div>
<div v-else>不及格</div>
<!-- 在 template 上使用 v-if 条件渲染多个元素 -->
<template v-if="isLoggedIn">
<p>欢迎回来,{{ username }}</p>
<button @click="isLoggedIn = false">退出登录</button>
</template>
<template v-else>
<p>请登录</p>
<button @click="isLoggedIn = true">登录</button>
</template>
</div>
</template>
<script setup>
import { ref } from 'vue'
const score = ref(0)
const isLoggedIn = ref(false)
const username = ref('张三')
</script>
2. v-show
根据表达式的真假值切换元素的显示与隐藏,通过 CSS display 属性实现,元素始终存在于 DOM 中:
<template>
<div>
<button @click="isVisible = !isVisible">
{{ isVisible ? '隐藏' : '显示' }}
</button>
<p v-show="isVisible">这段文字会被显示或隐藏</p>
</div>
</template>
<script setup>
import { ref } from 'vue'
const isVisible = ref(true)
</script>
3. v-if 与 v-show 的区别
v-if 是“真正”的条件渲染,条件为假时会销毁元素及事件监听器
v-show 只是简单切换 CSS 的 display 属性,元素始终存在
v-if 有更高的切换开销,适合条件不常变化的场景
v-show 有更高的初始渲染开销,适合需要频繁切换显示状态的场景
六、列表渲染
1. 基本用法(v-for)
使用 v-for 基于数组渲染列表,语法为 item in items:
<template>
<div>
<h3>商品列表</h3>
<ul>
<li v-for="product in products" :key="product.id">
{{ product.name }} - ¥{{ product.price }}
</li>
</ul>
<!-- 获取索引 -->
<h3>带索引的列表</h3>
<ul>
<li v-for="(item, index) in fruits" :key="index">
{{ index + 1 }}. {{ item }}
</li>
</ul>
<!-- 遍历对象 -->
<h3>对象属性遍历</h3>
<ul>
<li v-for="(value, key, index) in userInfo" :key="key">
{{ index + 1 }}. {{ key }}: {{ value }}
</li>
</ul>
</div>
</template>
<script setup>
import { ref, reactive } from 'vue'
const products = ref([
{ id: 1, name: '手机', price: 3999 },
{ id: 2, name: '电脑', price: 5999 }
])
const fruits = ref(['苹果', '香蕉', '橙子'])
const userInfo = reactive({
name: '张三',
age: 25,
city: '北京'
})
</script>
2. key 属性的重要性
使用 v-for 时,必须为每项提供唯一的 key 属性:
帮助 Vue 识别每个节点的身份,高效更新 DOM
避免使用索引作为 key(尤其是列表会被修改时),可能导致渲染错误
推荐使用数据中唯一且稳定的标识符(如 id)作为 key
3. 数组更新检测
Vue 能够检测到数组的变更并触发视图更新的方法:
变更方法(会修改原数组):push()、pop()、shift()、unshift()、splice()、sort()、reverse()
替换数组(返回新数组):filter()、concat()、slice() 等,需将结果重新赋值给原数组
<template>
<div>
<ul>
<li v-for="item in items" :key="item.id">{{ item.name }}</li>
</ul>
<button @click="addItem">添加项</button>
<button @click="removeItem">移除最后一项</button>
<button @click="filterItems">过滤项</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
const items = ref([
{ id: 1, name: '项 1' },
{ id: 2, name: '项 2' }
])
function addItem() {
// 变更方法
items.value.push({
id: Date.now(),
name: `新项 ${items.value.length + 1}`
})
}
function removeItem() {
// 变更方法
items.value.pop()
}
function filterItems() {
// 替换数组
items.value = items.value.filter(item => item.id % 2 === 0)
}
</script>
七、模板引用
使用 ref 属性获取 DOM 元素或组件实例的引用:
<template>
<div>
<input ref="inputRef" type="text">
<button @click="focusInput">聚焦输入框</button>
<child-component ref="childRef" />
<button @click="callChildMethod">调用子组件方法</button>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import ChildComponent from './ChildComponent.vue'
// 创建 ref 用于存储引用
const inputRef = ref(null)
const childRef = ref(null)
// 组件挂载后才能访问到 ref
onMounted(() => {
inputRef.value.focus()
})
function focusInput() {
inputRef.value.focus()
}
function callChildMethod() {
// 调用子组件暴露的方法
childRef.value?.childMethod()
}
</script>
注意:模板引用在组件挂载后才能访问,通常在 onMounted 钩子中使用。
八、总结
Vue3 的模板语法是其核心特性之一,提供了简洁而强大的方式来声明式地绑定数据和处理 DOM 交互。主要包括:
文本插值与原始 HTML 绑定
灵活的属性绑定(包括 class 和 style)
事件处理与修饰符
表单输入的双向绑定(v-model)
条件渲染(v-if / v-show)
列表渲染(v-for)
模板引用
1552

被折叠的 条评论
为什么被折叠?



