第 3 节:响应式数据与双向绑定
📚 本节目标
- 理解什么是"响应式"
- 掌握 v-model 指令的基本用法
- 学会在输入框、复选框、单选框中使用 v-model
- 理解 v-bind 和 v-model 的区别
一、什么是"响应式"?
传统 JavaScript 的方式
<input type="text" id="nameInput">
<p id="display"></p>
<script>
let name = '';
// 需要手动监听输入
document.getElementById('nameInput').addEventListener('input', function(e) {
name = e.target.value;
// 需要手动更新页面
document.getElementById('display').innerText = '你好,' + name;
});
</script>
问题:要写很多代码,手动监听、手动更新。
Vue 的响应式方式
<input type="text" v-model="name">
<p>你好,{{ name }}</p>
一行代码搞定! Vue 自动帮你:
- 监听输入框的变化
- 更新
name数据 - 更新页面显示
大白话解释"响应式":
- 数据变了,页面自动跟着变
- 页面变了(用户输入),数据也自动跟着变
- 这种"双向自动同步"就叫响应式
二、v-model 指令详解
基本用法:文本输入框
完整示例:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>v-model 基础示例</title>
<style>
.container {
max-width: 600px;
margin: 50px auto;
padding: 20px;
border: 2px solid #42b983;
border-radius: 10px;
}
input {
padding: 10px;
font-size: 16px;
width: 100%;
margin: 10px 0;
}
.result {
background: #f0f0f0;
padding: 15px;
border-radius: 5px;
margin-top: 20px;
}
</style>
</head>
<body>
<div id="app">
<div class="container">
<h2>自我介绍表单</h2>
<!-- 输入框与 name 数据双向绑定 -->
<label>你的名字:</label>
<input type="text" v-model="name" placeholder="请输入你的名字">
<label>你的年龄:</label>
<input type="number" v-model="age" placeholder="请输入你的年龄">
<!-- 实时显示数据 -->
<div class="result">
<h3>实时预览:</h3>
<p>姓名:{{ name }}</p>
<p>年龄:{{ age }}</p>
<p v-if="name">你好,{{ name }}!欢迎来到 Vue 的世界!</p>
</div>
</div>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
const { createApp } = Vue;
createApp({
data() {
return {
name: '', // 初始值为空字符串
age: '' // 初始值为空字符串
}
}
}).mount('#app');
</script>
</body>
</html>
预期效果:
- 在输入框中输入文字
- 下方的"实时预览"区域会立即更新
- 不需要点击任何按钮,完全自动!
v-model 与复选框
单个复选框:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>复选框示例</title>
<style>
.container {
max-width: 600px;
margin: 50px auto;
padding: 20px;
}
.checkbox-item {
margin: 15px 0;
}
</style>
</head>
<body>
<div id="app">
<div class="container">
<h2>用户协议</h2>
<div class="checkbox-item">
<!-- 绑定布尔值:勾选为 true,不勾选为 false -->
<label>
<input type="checkbox" v-model="agreed">
我已阅读并同意用户协议
</label>
</div>
<p>协议状态:{{ agreed ? '已同意' : '未同意' }}</p>
<!-- 根据是否勾选来禁用/启用按钮 -->
<button :disabled="!agreed">注册</button>
</div>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
const { createApp } = Vue;
createApp({
data() {
return {
agreed: false // 默认未勾选
}
}
}).mount('#app');
</script>
</body>
</html>
预期效果:
- 初始状态:按钮是灰色的(禁用状态)
- 勾选复选框后:按钮变成可点击
agreed的值会自动变成true或false
多个复选框:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>多复选框示例</title>
</head>
<body>
<div id="app">
<div class="container">
<h2>选择你喜欢的水果</h2>
<!-- 多个复选框绑定到同一个数组 -->
<label><input type="checkbox" v-model="fruits" value="苹果"> 苹果</label><br>
<label><input type="checkbox" v-model="fruits" value="香蕉"> 香蕉</label><br>
<label><input type="checkbox" v-model="fruits" value="橙子"> 橙子</label><br>
<label><input type="checkbox" v-model="fruits" value="葡萄"> 葡萄</label><br>
<p>你选择了:{{ fruits }}</p>
<p>共选择了 {{ fruits.length }} 种水果</p>
</div>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
const { createApp } = Vue;
createApp({
data() {
return {
fruits: [] // 空数组,勾选的值会自动添加进来
}
}
}).mount('#app');
</script>
</body>
</html>
预期效果:
- 勾选"苹果":
fruits变成['苹果'] - 再勾选"香蕉":
fruits变成['苹果', '香蕉'] - 取消勾选"苹果":
fruits变成['香蕉']
v-model 与单选框
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>单选框示例</title>
</head>
<body>
<div id="app">
<div class="container">
<h2>选择你的性别</h2>
<!-- 多个单选框绑定到同一个数据 -->
<label><input type="radio" v-model="gender" value="男"> 男</label>
<label><input type="radio" v-model="gender" value="女"> 女</label>
<p>你选择的性别是:{{ gender }}</p>
</div>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
const { createApp } = Vue;
createApp({
data() {
return {
gender: '' // 初始值为空
}
}
}).mount('#app');
</script>
</body>
</html>
预期效果:
- 点击"男":
gender变成'男' - 点击"女":
gender变成'女' - 单选框一次只能选一个
三、v-bind 和 v-model 的区别(重要)
这是新手最容易混淆的地方!
对比表格
| 特性 | v-bind(:) | v-model |
|---|---|---|
| 数据流向 | 单向:数据 → 页面 | 双向:数据 ⇄ 页面 |
| 用途 | 绑定属性(src、href 等) | 绑定表单输入 |
| 数据变化 | 页面会变,但用户操作不会改变数据 | 用户输入会自动改变数据 |
| 典型场景 | 显示图片、链接、样式 | 输入框、复选框、单选框 |
通俗比喻
v-bind:单向传话筒
- 你(数据)说话,观众(页面)听到
- 观众说话(用户操作),你听不到
v-model:双向对讲机
- 你说话,对方听到
- 对方说话,你也听到
代码对比
<!-- v-bind:只能从数据到页面 -->
<input :value="message"> <!-- 显示 message 的值,但输入不会改变 message -->
<!-- v-model:数据和页面双向同步 -->
<input v-model="message"> <!-- 显示 message 的值,输入会改变 message -->
试一试:
<div id="app">
<p>数据值:{{ message }}</p>
<!-- 用 v-bind,输入不会改变 message -->
<input :value="message" placeholder="用 v-bind">
<!-- 用 v-model,输入会改变 message -->
<input v-model="message" placeholder="用 v-model">
</div>
在第二个输入框输入,第一个输入框和文字都会更新!
四、综合练习:简单的问卷调查
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>问卷调查</title>
<style>
.survey {
max-width: 600px;
margin: 50px auto;
padding: 30px;
border: 2px solid #42b983;
border-radius: 10px;
background: #f9f9f9;
}
.question {
margin-bottom: 25px;
padding: 15px;
background: white;
border-radius: 5px;
}
.result {
background: #e7f7ed;
padding: 20px;
border-radius: 5px;
margin-top: 30px;
}
input, textarea {
margin: 5px 0;
}
textarea {
width: 100%;
padding: 10px;
}
</style>
</head>
<body>
<div id="app">
<div class="survey">
<h2>📝 Vue 学习问卷</h2>
<!-- 问题1:文本输入 -->
<div class="question">
<label><strong>1. 你的名字:</strong></label><br>
<input type="text" v-model="name" placeholder="请输入姓名">
</div>
<!-- 问题2:单选框 -->
<div class="question">
<strong>2. 你的编程经验:</strong><br>
<label><input type="radio" v-model="experience" value="新手"> 新手</label><br>
<label><input type="radio" v-model="experience" value="有一点基础"> 有一点基础</label><br>
<label><input type="radio" v-model="experience" value="比较熟练"> 比较熟练</label>
</div>
<!-- 问题3:多选框 -->
<div class="question">
<strong>3. 你想学习哪些内容?(可多选)</strong><br>
<label><input type="checkbox" v-model="interests" value="组件"> 组件开发</label><br>
<label><input type="checkbox" v-model="interests" value="路由"> Vue Router</label><br>
<label><input type="checkbox" v-model="interests" value="状态管理"> Pinia 状态管理</label><br>
<label><input type="checkbox" v-model="interests" value="项目实战"> 项目实战</label>
</div>
<!-- 问题4:多行文本 -->
<div class="question">
<strong>4. 对课程的建议:</strong><br>
<textarea v-model="suggestion" rows="4" placeholder="写下你的建议..."></textarea>
</div>
<!-- 问题5:复选框(同意) -->
<div class="question">
<label>
<input type="checkbox" v-model="agreed">
我同意提交这份问卷
</label>
</div>
<!-- 提交按钮 -->
<button :disabled="!agreed" @click="submit">提交问卷</button>
<!-- 实时预览 -->
<div class="result" v-if="name">
<h3>📊 你的回答预览:</h3>
<p><strong>姓名:</strong>{{ name }}</p>
<p><strong>编程经验:</strong>{{ experience }}</p>
<p><strong>学习兴趣:</strong>{{ interests.join('、') || '未选择' }}</p>
<p><strong>建议:</strong>{{ suggestion || '无' }}</p>
</div>
</div>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
const { createApp } = Vue;
createApp({
data() {
return {
name: '',
experience: '',
interests: [],
suggestion: '',
agreed: false
}
},
methods: {
submit() {
alert('问卷提交成功!感谢 ' + this.name + ' 的参与!');
}
}
}).mount('#app');
</script>
</body>
</html>
预期效果:
- 填写表单时,下方实时显示你的回答
- 必须勾选"同意"才能提交
- 点击提交后弹出提示
五、本节重点回顾
✅ 响应式 = 数据变页面变,页面变数据也变
✅ v-model = 双向数据绑定,用于表单元素
✅ v-bind = 单向数据绑定,用于标签属性
v-model 用法总结
| 表单元素 | 绑定的数据类型 | 示例 |
|---|---|---|
| 文本输入框 | 字符串 | <input v-model="name"> |
| 数字输入框 | 字符串/数字 | <input type="number" v-model="age"> |
| 单个复选框 | 布尔值 | <input type="checkbox" v-model="agreed"> |
| 多个复选框 | 数组 | <input type="checkbox" v-model="arr" value="A"> |
| 单选框 | 字符串 | <input type="radio" v-model="gender" value="男"> |
| 多行文本框 | 字符串 | <textarea v-model="text"></textarea> |
六、练习题
练习 1:制作一个简单的计算器输入界面
创建两个数字输入框和一个结果显示区域,实时显示两数之和。
提示:
data() {
return {
num1: 0,
num2: 0
}
}
在页面上显示 {{ num1 + num2 }}
点击查看完整答案
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>简易计算器</title>
</head>
<body>
<div id="app">
<h2>加法计算器</h2>
<input type="number" v-model.number="num1"> +
<input type="number" v-model.number="num2"> =
<strong>{{ num1 + num2 }}</strong>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
const { createApp } = Vue;
createApp({
data() {
return {
num1: 0,
num2: 0
}
}
}).mount('#app');
</script>
</body>
</html>
注意:v-model.number 可以自动将输入转换为数字类型。
练习 2:兴趣爱好选择器
创建一个页面,包含:
- 多个复选框(至少 4 个爱好选项)
- 实时显示已选择的爱好数量
- 如果没选任何爱好,显示提示"请至少选择一项"
点击查看答案
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>兴趣爱好选择</title>
</head>
<body>
<div id="app">
<h2>选择你的兴趣爱好</h2>
<label><input type="checkbox" v-model="hobbies" value="阅读"> 阅读</label><br>
<label><input type="checkbox" v-model="hobbies" value="运动"> 运动</label><br>
<label><input type="checkbox" v-model="hobbies" value="音乐"> 音乐</label><br>
<label><input type="checkbox" v-model="hobbies" value="旅游"> 旅游</label><br>
<p v-if="hobbies.length === 0" style="color: orange;">
⚠️ 请至少选择一项爱好
</p>
<p v-else>
你选择了 {{ hobbies.length }} 项爱好:{{ hobbies.join('、') }}
</p>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
const { createApp } = Vue;
createApp({
data() {
return {
hobbies: []
}
}
}).mount('#app');
</script>
</body>
</html>
🎉 恭喜你完成第三节课!
下一节我们将学习:事件处理 —— 学会使用 v-on 指令处理用户的点击、输入等操作。