Skip to content

案例 - 选择

小选影响全选

需求:小选框都选中 (手选), 全选自动选中

分析:

  1. 先静态后动态,从拿到静态标签和数据
  2. 循环生成复选框和文字,对象的 c 属性和小选框的选中状态,用 v-model 双向绑定
  3. 定义 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>

全选影响小选

  1. 获取到全选状态 – 改装 isAll 计算属性
  2. 全选状态同步给所有小选框

分析:

  1. : isAll 改成完整写法,set 里获取到全选框,勾选的状态值
  2. : 遍历数据数组,赋给所有小选框 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)
    }
})

反选

需求:点击反选,让所有小选框,各自取相反勾选状态

分析:

  1. 小选框的勾选状态,在对象的 c 属性
  2. 遍历所有对象,把对象的 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 }} &nbsp;&nbsp;
        </label>
      </div>
      <p>你选中的元素,累加的值和为:{{ total }}</p>
    </div>
    <button @click="submit">提交</button>
  </div>
</template>

<style scoped></style>

总结,当计算属性函数里引用的 vue 变量发生改变,函数就执行并重新返回结果并缓存起来

学生信息管理

如果 1 个按钮不会写,用 2 个按钮写

目标:

  1. 铺设页面,准备初始的数据 (自己手写数据结构) - 前面是数组索引 +1 *作为序号
  2. 当输入框没有值,要给用户一个提示,必须都有值才能增加新数据 (数据驱动页面哦)
  3. 添加功能 - 想好数据结构统一对象的 key
  4. 点击编辑功能,把值赋予到输入框上 (不要操作 dom, 数据驱动页面)
  5. 用户修改后,点击相同按钮 - 想想怎么判断怎么是添加还是修改的功能 (提示:准备一个全局变量, 点过编辑按钮可以让它为 true) - 实现编辑后更新页面效果
  6. 点击删除,删除这行数据
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>