第一章:初识复选框——从前有个“多情”的输入框
还记得那些年我们追过的JavaScript吗?当遇到复选框时,我们得这样苦口婆心地劝说:
// 传统的JS方式,累死个人!
const checkboxes = document.querySelectorAll('input[type="checkbox"]');
let selectedValues = [];
checkboxes.forEach(checkbox => {
checkbox.addEventListener('change', function() {
if (this.checked) {
selectedValues.push(this.value);
} else {
const index = selectedValues.indexOf(this.value);
if (index > -1) {
selectedValues.splice(index, 1);
}
}
console.log('当前选中的值:', selectedValues);
});
});
光是写这段代码,我就已经想念Vue了!来看看Vue是怎么“宠幸”我们的:
<template>
<div>
<input type="checkbox" v-model="isChecked"> 同意协议
<p>当前状态:{{ isChecked ? '已同意' : '未同意' }}</p>
</div>
</template>
<script>
export default {
data() {
return {
isChecked: false
}
}
}
</script>
v-model就像个贴心的红娘,在复选框和数据之间牵线搭桥。当你在页面上勾选时,isChecked自动变成true;取消勾选时,它又乖巧地变回false。
第二章:单个复选框——单身贵族的自我修养
单个复选框虽然简单,但人家可是有自己的小脾气的!
场景一:注册协议同意框
<template>
<div class="register-form">
<h3>注册新用户</h3>
<div class="agreement">
<input
type="checkbox"
id="agree"
v-model="formData.agreed"
true-value="yes"
false-value="no"
>
<label for="agree">我已阅读并同意《用户协议》</label>
</div>
<button :disabled="!formData.agreed" @click="handleSubmit">
立即注册
</button>
<p>协议状态:{{ formData.agreed }}</p>
<p>按钮是否可用:{{ !formData.agreed ? '不可用' : '可用' }}</p>
</div>
</template>
<script>
export default {
data() {
return {
formData: {
agreed: 'no' // 默认不同意
}
}
},
methods: {
handleSubmit() {
if (this.formData.agreed === 'yes') {
alert('注册成功!');
// 这里可以提交表单
}
}
}
}
</script>
知识点敲黑板:
true-value和false-value就像给复选框的两种状态起了个小名- 默认情况下,选中时值为
true,未选中为false - 使用自定义值后,选中的值变成
"yes",未选中变成"no"
第三章:多个复选框——后宫选妃大戏开场
当多个复选框同时出现,那场面就像皇帝选妃——你得知道选了哪些,没选哪些!
场景二:兴趣选择(多选)
<template>
<div class="interest-select">
<h3>请选择你的兴趣爱好(可多选):</h3>
<div class="interest-options">
<label v-for="interest in interests" :key="interest.value">
<input
type="checkbox"
:value="interest.value"
v-model="selectedInterests"
>
{{ interest.label }}
</label>
</div>
<div class="selection-result">
<h4>你选择了:</h4>
<ul>
<li v-for="selected in selectedInterests" :key="selected">
{{ getInterestLabel(selected) }}
</li>
</ul>
<p v-if="selectedInterests.length === 0">还没有选择任何兴趣</p>
</div>
</div>
</template>
<script>
export default {
data() {
return {
interests: [
{ value: 'reading', label: '阅读' },
{ value: 'music', label: '音乐' },
{ value: 'sports', label: '运动' },
{ value: 'travel', label: '旅行' },
{ value: 'gaming', label: '游戏' }
],
selectedInterests: [] // 注意:这里是数组!
}
},
methods: {
getInterestLabel(value) {
const interest = this.interests.find(item => item.value === value);
return interest ? interest.label : '';
}
}
}
</script>
重要提醒:多个复选框绑定时,v-model必须绑定到数组! 如果你不小心绑定到字符串或者布尔值,Vue会默默哭泣——它不知道该把多个值往哪里放。
第四章:实战进阶——超市购物车案例
理论说再多,不如来个实战!让我们模拟一个超市购物车:
<template>
<div class="shopping-cart">
<h2>🛒 超市购物车</h2>
<div class="products">
<div
v-for="product in products"
:key="product.id"
class="product-item"
:class="{ selected: isProductSelected(product.id) }"
>
<label class="product-select">
<input
type="checkbox"
:value="product.id"
v-model="selectedProducts"
@change="updateTotal"
>
{{ product.name }} - ¥{{ product.price }}
</label>
<div class="quantity" v-if="isProductSelected(product.id)">
数量:
<input
type="number"
v-model.number="product.quantity"
min="1"
@change="updateTotal"
>
</div>
</div>
</div>
<div class="cart-summary">
<h3>购物车汇总</h3>
<p>已选商品:{{ selectedProducts.length }} 件</p>
<p>总金额:¥{{ totalAmount }}</p>
<p v-if="selectedProducts.length > 0">
最贵的商品:{{ mostExpensiveProduct }}
</p>
<button
:disabled="selectedProducts.length === 0"
@click="checkout"
>
结算({{ selectedProducts.length }}件商品)
</button>
</div>
</div>
</template>
<script>
export default {
data() {
return {
products: [
{ id: 1, name: '苹果', price: 8, quantity: 1 },
{ id: 2, name: '香蕉', price: 5, quantity: 1 },
{ id: 3, name: '橙子', price: 6, quantity: 1 },
{ id: 4, name: '葡萄', price: 12, quantity: 1 }
],
selectedProducts: [],
totalAmount: 0
}
},
computed: {
mostExpensiveProduct() {
if (this.selectedProducts.length === 0) return '';
const selectedProductDetails = this.products.filter(
product => this.selectedProducts.includes(product.id)
);
const mostExpensive = selectedProductDetails.reduce((max, product) => {
return product.price > max.price ? product : max;
});
return mostExpensive.name;
}
},
methods: {
isProductSelected(productId) {
return this.selectedProducts.includes(productId);
},
updateTotal() {
this.totalAmount = this.selectedProducts.reduce((total, productId) => {
const product = this.products.find(p => p.id === productId);
return total + (product.price * product.quantity);
}, 0);
},
checkout() {
const selectedItems = this.products.filter(
product => this.selectedProducts.includes(product.id)
);
alert(`结算成功!\n商品:${selectedItems.map(item =>
`${item.name}×${item.quantity}`
).join(',')}\n总金额:¥${this.totalAmount}`);
}
}
}
</script>
<style scoped>
.product-item {
padding: 10px;
margin: 5px 0;
border: 1px solid #ddd;
border-radius: 5px;
}
.product-item.selected {
background-color: #f0f8ff;
border-color: #1890ff;
}
.quantity {
margin-top: 5px;
}
.quantity input {
width: 60px;
padding: 2px 5px;
}
</style>
这个案例涵盖了:
- 复选框选择商品
- 动态显示数量输入框
- 实时计算总金额
- 查找最贵商品
- 结算功能
第五章:高级玩法——自定义三态复选框
有时候,我们需要一个"半选"状态,比如全选功能中的 indeterminate 状态:
<template>
<div class="tri-state-checkbox">
<h3>权限设置(三态演示)</h3>
<div class="permission-group">
<label class="main-permission">
<input
type="checkbox"
ref="mainCheckbox"
v-model="mainState"
@change="handleMainChange"
>
系统管理权限
</label>
<div class="sub-permissions">
<label v-for="permission in permissions" :key="permission.id">
<input
type="checkbox"
:value="permission.id"
v-model="selectedPermissions"
@change="updateMainState"
>
{{ permission.name }}
</label>
</div>
</div>
<p>主复选框状态:{{ mainState }}</p>
<p>选中的子权限:{{ selectedPermissions }}</p>
</div>
</template>
<script>
export default {
data() {
return {
permissions: [
{ id: 'user_manage', name: '用户管理' },
{ id: 'role_manage', name: '角色管理' },
{ id: 'log_view', name: '日志查看' }
],
selectedPermissions: [],
mainState: false
}
},
mounted() {
this.updateMainState();
},
methods: {
updateMainState() {
const total = this.permissions.length;
const selected = this.selectedPermissions.length;
if (selected === 0) {
this.mainState = false;
this.$refs.mainCheckbox.indeterminate = false;
} else if (selected === total) {
this.mainState = true;
this.$refs.mainCheckbox.indeterminate = false;
} else {
this.mainState = false;
this.$refs.mainCheckbox.indeterminate = true;
}
},
handleMainChange() {
if (this.mainState) {
// 选中所有
this.selectedPermissions = this.permissions.map(p => p.id);
} else {
// 取消所有
this.selectedPermissions = [];
}
}
}
}
</script>
三态复选框的精髓:
indeterminate属性控制"半选"状态- 通过计算选中数量来决定主复选框状态
- 主复选框控制所有子复选框
第六章:避坑指南——复选框的那些"坑"
- 数组初始化问题
// ❌ 错误做法
data() {
return {
selectedItems: '' // 应该用数组!
}
}
// ✅ 正确做法
data() {
return {
selectedItems: [] // 多个复选框必须用数组
}
}
- v-model值类型问题
<!-- ❌ 值类型不一致 -->
<input type="checkbox" value="1" v-model="selectedIds">
<input type="checkbox" value="2" v-model="selectedIds">
<!-- ✅ 保持值类型一致 -->
<input type="checkbox" :value="1" v-model="selectedIds">
<input type="checkbox" :value="2" v-model="selectedIds">
- 动态生成复选框的key问题
<!-- ❌ 缺少key -->
<label v-for="item in list">
<input type="checkbox" :value="item.id" v-model="selected">
{{ item.name }}
</label>
<!-- ✅ 添加key -->
<label v-for="item in list" :key="item.id">
<input type="checkbox" :value="item.id" v-model="selected">
{{ item.name }}
</label>
第七章:完整示例大放送
最后,给大家一个完整的、可运行的示例:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Vue复选框绑定完整示例</title>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<style>
body { font-family: 'Microsoft YaHei', sans-serif; padding: 20px; }
.container { max-width: 800px; margin: 0 auto; }
.section { margin-bottom: 30px; padding: 20px; border: 1px solid #e1e1e1; border-radius: 8px; }
.checkbox-group label { display: block; margin: 8px 0; cursor: pointer; }
.selected { background: #e3f2fd; padding: 10px; border-radius: 4px; margin-top: 10px; }
button { padding: 10px 20px; background: #2196f3; color: white; border: none; border-radius: 4px; cursor: pointer; }
button:disabled { background: #ccc; cursor: not-allowed; }
</style>
</head>
<body>
<div id="app" class="container">
<h1>🎯 Vue复选框绑定实战大全</h1>
<!-- 单个复选框示例 -->
<div class="section">
<h2>1. 单个复选框 - 协议同意</h2>
<label>
<input type="checkbox" v-model="singleCheckbox">
我同意《霸王条款》
</label>
<p>状态:{{ singleCheckbox ? '已同意' : '未同意' }}</p>
</div>
<!-- 多个复选框示例 -->
<div class="section">
<h2>2. 多个复选框 - 技能选择</h2>
<div class="checkbox-group">
<label v-for="skill in skills" :key="skill.id">
<input type="checkbox" :value="skill.id" v-model="selectedSkills">
{{ skill.name }}
</label>
</div>
<div class="selected">
<p>已选技能:</p>
<ul>
<li v-for="skillId in selectedSkills" :key="skillId">
{{ getSkillName(skillId) }}
</li>
</ul>
<p v-if="selectedSkills.length === 0">还没有选择任何技能</p>
</div>
</div>
<!-- 自定义值示例 -->
<div class="section">
<h2>3. 自定义值 - 订阅设置</h2>
<label>
<input
type="checkbox"
v-model="subscription"
true-value="subscribed"
false-value="unsubscribed"
>
接收促销邮件
</label>
<p>订阅状态:{{ subscription }}</p>
</div>
<!-- 操作按钮 -->
<div class="section">
<button @click="submitForm">提交表单</button>
<button @click="resetForm" style="margin-left: 10px; background: #ff9800;">重置</button>
</div>
<!-- 结果显示 -->
<div class="section" v-if="submitted">
<h2>📋 提交结果</h2>
<p>协议同意:{{ submissionData.agreed ? '是' : '否' }}</p>
<p>选择技能:{{ submissionData.skills.join('、') }}</p>
<p>订阅状态:{{ submissionData.subscription }}</p>
</div>
</div>
<script>
const { createApp, ref } = Vue;
createApp({
setup() {
// 单个复选框
const singleCheckbox = ref(false);
// 多个复选框
const skills = ref([
{ id: 1, name: 'Vue.js' },
{ id: 2, name: 'React' },
{ id: 3, name: 'Angular' },
{ id: 4, name: 'Node.js' }
]);
const selectedSkills = ref([]);
// 自定义值
const subscription = ref('unsubscribed');
// 提交状态
const submitted = ref(false);
const submissionData = ref({});
const getSkillName = (skillId) => {
const skill = skills.value.find(s => s.id === skillId);
return skill ? skill.name : '未知技能';
};
const submitForm = () => {
submissionData.value = {
agreed: singleCheckbox.value,
skills: selectedSkills.value.map(getSkillName),
subscription: subscription.value
};
submitted.value = true;
alert('表单提交成功!请查看提交结果。');
};
const resetForm = () => {
singleCheckbox.value = false;
selectedSkills.value = [];
subscription.value = 'unsubscribed';
submitted.value = false;
};
return {
singleCheckbox,
skills,
selectedSkills,
subscription,
submitted,
submissionData,
getSkillName,
submitForm,
resetForm
};
}
}).mount('#app');
</script>
</body>
</html>
结语:复选框与Vue的"婚后生活"
通过这次深度探索,相信你已经掌握了Vue复选框绑定的精髓。从简单的单个复选框到复杂的多选场景,再到高级的三态控制,v-model就像个贴心的管家,帮你处理所有的状态同步。
记住:单个复选框绑定到布尔值,多个复选框绑定到数组,这是避免踩坑的关键!
现在,去和Vue的复选框开启你们的"甜蜜联姻"吧!如果遇到问题,记得回来看这份"婚姻指南"哦~
7273

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



