案例 - 选择
小选影响全选
需求:小选框都选中 (手选), 全选自动选中
分析:
- 先静态后动态,从拿到静态标签和数据
- 循环生成复选框和文字,对象的 c 属性和小选框的选中状态,用 v-model 双向绑定
- 定义 isAll 计算属性,值通过小选框们统计 c 属性状态得来
模板标签和数据 (直接复制在这基础上写 vue 代码)
vue
<script setup>
import { reactive } from "vue";
const items = reactive([
{ name: "猪八戒", c: false },
{ name: "孙悟空", c: false },
{ name: "唐僧", c: false },
{ name: "白龙马", c: false },
]);
</script>
<template>
<div class="container">
<div>
全选:
<input class="form-check-input" type="checkbox" value="" />
<button class="small">反选</button>
</div>
<div class="form-check">
<input
class="form-check-input"
type="checkbox"
value=""
id="flexCheckDefault"
/>
<label class="form-check-label" for="flexCheckDefault"> 任务名 </label>
</div>
</div>
</template>
答案
vue
<script setup>
import { computed, reactive } from "vue";
// 目标:小选框 -> 全选
// 1. 标签 + 样式+js 准备好
// 2. 把数据循环展示到页面上
const items = reactive([
{ name: "猪八戒", c: false },
{ name: "孙悟空", c: false },
{ name: "唐僧", c: false },
{ name: "白龙马", c: false },
]);
// 6. 统计小选框状态 -> 全选状态
// every 口诀:查找数组里"不符合"条件,直接原地返回 false
const is_all = computed(() => {
return items.every((item) => item.c === true);
});
</script>
<template>
<div class="container">
<div>
全选:
<!-- 4. v-model 关联全选 - 选中状态 -->
<input class="form-check-input" type="checkbox" v-model="is_all" />
<button class="small">反选</button>
</div>
<div class="form-check" v-for="(item, index) in items">
<!-- 3. 对象.c - 关联 选中状态 -->
<input
class="form-check-input"
type="checkbox"
value=""
:id="'item-' + index"
v-model="item.c"
/>
<label class="form-check-label" :for="'item-' + index">
{{ item.name }}
</label>
</div>
</div>
</template>
全选影响小选
- 获取到全选状态 – 改装 isAll 计算属性
- 全选状态同步给所有小选框
分析:
- : isAll 改成完整写法,set 里获取到全选框,勾选的状态值
- : 遍历数据数组,赋给所有小选框 v-model 关联的属性
答案
JavaScript
const is_all = computed({
// 6. 统计小选框状态 -> 全选状态
// every口诀: 查找数组里"不符合"条件, 直接原地返回false
get: () => {
return items.every(item => item.c === true)
},
// 7. 全选框 - 选中状态(true/false)
set: val => {
items.forEach(obj => obj.c = val)
}
})
反选
需求:点击反选,让所有小选框,各自取相反勾选状态
分析:
- 小选框的勾选状态,在对象的 c 属性
- 遍历所有对象,把对象的 c 属性取相反值赋予回去即可
js
// 8. 让数组里对象的 c 属性取反再赋予回去
const revers_all = () => {
items.forEach((obj) => (obj.c = !obj.c));
};
选择求和
需求:把用户选中的数字,累计求和显示
提示:v-model 绑定的变量是数组,可以收集 checkbox 的 value 属性
js
[9, 15, 19, 25, 29, 31, 48, 57, 62, 79, 87];
答案
vue
<script setup>
import { computed, reactive, ref, watch } from "vue";
const data = reactive({
arr: [9, 15, 19, 25, 29, 31, 48, 57, 62, 79, 87],
check_num_arr: [],
});
const total = computed(() => {
return data.check_num_arr.reduce((sum, val) => {
return (sum += val);
}, 0);
});
const submit = () => {
console.log(data);
};
</script>
<template>
<div class="container">
<div>
<!-- 无 id 时,可以使用 index(反正也是就地更新) -->
<div v-for="(item, index) in data.arr" style="display: inline-block">
<label>
<input type="checkbox" v-model="data.check_num_arr" :value="item" />
{{ item }}
</label>
</div>
<p>你选中的元素,累加的值和为:{{ total }}</p>
</div>
<button @click="submit">提交</button>
</div>
</template>
<style scoped></style>
总结,当计算属性函数里引用的 vue 变量发生改变,函数就执行并重新返回结果并缓存起来
学生信息管理
如果 1 个按钮不会写,用 2 个按钮写
目标:
- 铺设页面,准备初始的数据 (自己手写数据结构) - 前面是数组索引 +1 *作为序号
- 当输入框没有值,要给用户一个提示,必须都有值才能增加新数据 (数据驱动页面哦)
- 添加功能 - 想好数据结构统一对象的 key
- 点击编辑功能,把值赋予到输入框上 (不要操作 dom, 数据驱动页面)
- 用户修改后,点击相同按钮 - 想想怎么判断怎么是添加还是修改的功能 (提示:准备一个全局变量, 点过编辑按钮可以让它为 true) - 实现编辑后更新页面效果
- 点击删除,删除这行数据
vue
<script setup>
import { computed, reactive, ref, watch } from "vue";
</script>
<template>
<div id="container">
<div>
<label>姓名:<input type="text" /></label>
</div>
<div>
<label>年龄:<input type="text" /></label>
</div>
<div>
<label
>性别:
<select>
<option value="男">男</option>
<option value="女">女</option>
</select>
</label>
</div>
<div>
<button>添加/修改</button>
</div>
<div>
<table class="table table-bordered table-hover mt-2">
<tr>
<th>序号</th>
<th>姓名</th>
<th>年龄</th>
<th>性别</th>
<th>操作</th>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td>
<button>删除</button>
<button>编辑</button>
</td>
</tr>
</table>
</div>
</div>
</template>
答案
vue
<script setup>
import { computed, reactive, ref, watch } from "vue";
const user = reactive({
id: 0,
username: "",
age: 0,
gender: "",
});
const user_list = reactive([]);
const add_user = () => {
if (user.id === 0) {
user.id = user_list.length > 0 ? user_list[user_list.length - 1].id + 1 : 1;
user_list.push(JSON.parse(JSON.stringify(user)));
} else {
let index = user_list.findIndex((ele) => {
return ele.id === user.id;
});
Object.assign(user_list[index], user);
}
Object.assign(user, {
id: 0,
username: "",
age: 0,
gender: "",
});
};
const del_user = (id) => {
let index = user_list.findIndex((ele) => {
return ele.id === id;
});
user_list.splice(index, 1);
};
const edit_user = (id) => {
let item = user_list.find((ele) => {
return ele.id === id;
});
Object.assign(user, item);
};
</script>
<template>
<div id="container">
<div>
<label>姓名:<input type="text" v-model="user.username" /></label>
</div>
<div>
<label>年龄:<input type="text" v-model="user.age" /></label>
</div>
<div>
<label
>性别:
<select v-model="user.gender">
<option value="男">男</option>
<option value="女">女</option>
</select>
</label>
</div>
<div>
<button @click="add_user">添加/修改</button>
</div>
<div>
<table class="table table-bordered table-hover mt-2">
<tr>
<th>序号</th>
<th>姓名</th>
<th>年龄</th>
<th>性别</th>
<th>操作</th>
</tr>
<tr v-for="item in user_list">
<td>{{ item.id }}</td>
<td>{{ item.name }}</td>
<td>{{ item.age }}</td>
<td>{{ item.gender }}</td>
<td>
<button @click="del_user(item.id)">删除</button>
<button @click="edit_user(item.id)">编辑</button>
</td>
</tr>
</table>
</div>
</div>
</template>