全选、小选和反选的实现

432 阅读2分钟

一、原生如何实现全选、小选和反选

1.全选、全不选、反选(低配版)

需求分析:

  • 点击全选:设置每一个选择框的 checkedtrue
  • 点击全不选:设置每一个选择框的 checkedfalse
  • 点击反选:设置每一个选择框的 checked 与自身相反
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <input id="checkAll" type="button" value="全选" />
    <input id="unCheckAll" type="button" value="全不" />
    <input id="reverseCheck" type="button" value="反选" />
    <br>
    <input class="check" type="checkbox" />吃饭
    <input class="check" type="checkbox" />睡觉
    <input class="check" type="checkbox" />敲代码
    <input class="check" type="checkbox" />看书
    <input class="check" type="checkbox" />玩魔方
    <script>
        // 1.获取元素
        let checkList = document.querySelectorAll('.check')//获取所有复选框(伪数组)
        let checkAll = document.querySelector('#checkAll')//获取全选按钮
        let unCheckAll = document.querySelector('#unCheckAll')//获取全不选按钮
        let reverseCheck = document.querySelector('#reverseCheck')//获取反选按钮

        // 2.注册事件
        // 2.1 全选
        checkAll.onclick = function () {
            // ◆设置每一个选择框的 checked 为 true
            for (let i = 0; i < checkList.length; i++) {
                checkList[i].checked = true
            }
        }

        //2.2 全不选
        unCheckAll.onclick = function () {
            // ◆设置每一个选择框的 checked 为 false
            for (let i = 0; i < checkList.length; i++) {
                checkList[i].checked = false
            }
        }

        //2.3 反选
        reverseCheck.onclick = function () {
            //3.◆设置每一个选择框的 checked 与自身相反
            for (let i = 0; i < checkList.length; i++) {
                checkList[i].checked = !checkList[i].checked
            }
        }
    </script>
</body>

</html>

2.全选、反选、小选(高配版)

需求分析:

  • 点击全选:设置小选框的 checked 值与自身 一致
  • 点击反选:设置每一个选择框的 checked 与自身相反
  • 点击小选: 判断全选的 checked
    • 小选框的checked 全部为 true,全选才为 true
    • 小选框只要有一个没有勾选就是,全选就是 false
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <input id="checkAll" type="checkbox" />全选
    <input id="reverseCheck" type="checkbox" />反选
    <br>
    <input class="check" type="checkbox" />吃饭
    <input class="check" type="checkbox" />睡觉
    <input class="check" type="checkbox" />敲代码
    <input class="check" type="checkbox" />看书
    <input class="check" type="checkbox" />玩魔方
    <script>
        // 1.获取元素
        let checkList = document.querySelectorAll('.check')//获取所有复选框(伪数组)
        let checkAll = document.querySelector('#checkAll')//获取全选按钮
        let reverseCheck = document.querySelector('#reverseCheck')//获取反选按钮


        //2.注册事件

        //2.1 点击全选
        checkAll.onclick = function () {
            // ◆设置小选框的 checked 值与自身一致
            for (let i = 0; i < checkList.length; i++) {
                checkList[i].checked = this.checked
            }
        }

        //2.2 点击反选
        reverseCheck.onclick = function () {
            // ◆设置每一个选择框的 checked 与自身相反
            for (let i = 0; i < checkList.length; i++) {
                checkList[i].checked = !checkList[i].checked
            }
        }

        // //2.2 点击小选(法一:累加和思想)
        // for (let i = 0; i < checkList.length; i++) {
        //     checkList[i].onclick = function () {
        //         // (1)先求选中的总数量
        //         let sum = 0
        //         for (let j = 0; j < checkList.length; j++) {
        //             // 只要有一个勾选了,sum++
        //             if (checkList[j].checked) {
        //                 sum++
        //             }
        //         }
        //         // (2)判断选中的数量与选择框数量是否一致
        //         checkAll.checked = (sum === checkList.length)
        //     }
        // }

        //2.2 点击小选(法二:开关思想)
        for (let i = 0; i < checkList.length; i++) {
            checkList[i].onclick = function () {
                // (1)声明开关变量
                let flag = true
                // (2)遍历数组检查开关
                for (let i = 0; i < checkList.length; i++) {
                    // 只要有一个没勾选,flag 就变为 false
                    if (!checkList[i].checked) {
                        flag = false
                        break// ◆中止循环
                    }
                }
                // (3)把开关结果赋值给全选的 checked 值
                checkAll.checked = flag
            }
        }
    </script>
</body>

</html>

二、使用 vue2 实现全选、小选和反选

<template>
  <div>
    <label> <input v-model="isAll" type="checkbox" />全选</label>
    <label> <input type="checkbox" @change="revCheck" />反选</label><br />
    <div v-for="item in list" :key="item.code">
      <!-- <input :id="item.code" type="checkbox" v-model="item.state" /><label :for="item.code">{{ item.hobby }}</label> -->
      <!-- <label :for="item.code"> <input type="checkbox" :id="item.code">{{item.hobby}}</label> -->
      <label><input type="checkbox" v-model="item.state" />{{ item.hobby }}</label>
    </div>
  </div>
</template>

<script>
export default {
  data () {
    return {
      list: [
        { hobby: '吃饭', code: 1, state: false },
        { hobby: '睡觉', code: 2, state: false },
        { hobby: '敲代码', code: 3, state: true },
        { hobby: '看书', code: 4, state: false },
        { hobby: '玩魔方', code: 5, state: true }
      ]
    }
  },
  computed: {
    isAll: {
      // ◆全选影响小选
      set (val) {
        this.list.forEach((item) => {
          item.state = val
        })
      },
      // ◆小选影响全选
      get () {
        return this.list.every((item) => item.state)
      }
    }
  },
  methods: {
    // ◆反选影响小选
    revCheck () {
      this.list.forEach((item) => {
        item.state = !item.state
      })
    }
  }
}
</script>

三、使用 vue3 实现全选、小选和反选

<template>
  <div>
    <label> <input v-model="isAll" type="checkbox" />全选</label>
    <label> <input type="checkbox" @change="revCheck" /> 反选</label><br />
    <div v-for="item in list" :key="item.code">
      <!-- <input :id="item.code" type="checkbox" v-model="item.state" /><label :for="item.code">{{ item.hobby }}</label> -->
      <label><input type="checkbox" v-model="item.state" />{{ item.hobby }}</label>
    </div>
  </div>
</template>

<script>
import { ref, computed } from "vue";
export default {
  setup() {
   const list = ref([
      { hobby: '吃饭', code: 1, state: false },
      { hobby: '睡觉', code: 2, state: false },
      { hobby: '敲代码', code: 3, state: true },
      { hobby: '看书', code: 4, state: false },
      { hobby: '玩魔方', code: 5, state: true }
    ])
    
    const isAll = computed({
      // ◆全选影响小选
      set(val) {
        list.value.forEach((item) => {
          item.state = val
        })
      },
      // ◆小选影响全选
      get() {
        return list.value.every((item) => item.state)
      }
    })

     // ◆反选影响小选
    const revCheck = () => {
      list.value.forEach((item) => {
        item.state = !item.state
      })
    }
    return { list, isAll, revCheck }
  }
}
</script>

四、react 实现 全选、反选、小选

// react 实现全选、反选、小选
import React, { useState, useEffect } from 'react'

const CheckBox = () => {
    const arr = [
        { id: 1, hobby: '吃饭', state: true },
        { id: 2, hobby: '睡觉', state: false },
        { id: 3, hobby: '敲代码', state: true },
        { id: 4, hobby: '玩魔方', state: false }
    ]
    const [list, setList] = useState(arr)
    // ◆ 一进入页面获取 localStorage 里面存储的数据,没有就用 arr
    // 相当于 componentDidMount 
    useEffect(() => {
        setList((arr) => {
            return  JSON.parse(localStorage.getItem('list')) || arr
        })
    }, [])
    // ◆小选框是否选中的状态
    const singleChangeHandler = (id, flag) => {
        console.log(id, flag, '小选框')
        setList((list) => {
            return list.map(item => {
                if (item.id === id) {
                    return {
                        ...item,
                        state: flag
                    }
                } else {
                    return item
                }
            })
        })
    }

    const [flag, setFlag] = useState(false)
    // ◆全选/全不选
    const checkAllHandler = (isCheck) => {
        // 1.先设置自己的 checked 值
        setFlag(isCheck)
        // 2.循环其他复选框的值和自己一样
        setList((list) => {
            return list.map(item => {
                return {
                    ...item,
                    state: isCheck
                }
            })
        })
    }

    // ◆小选影响全选 (相当于 componentDidUpdate)
    useEffect(() => {
        // 1.只要有一个小选框没选中,全选就是 false,否则 true
        setFlag(() => list.every(item => item.state))
        // 2.持久化存储 localStorage
        localStorage.setItem('list', JSON.stringify(list))
    }, [list])

    // ◆反选
    const revCheckHandler = () => {
        setList((list) => {
            return list.map(item => {
                return {
                    ...item,
                    state: !item.state
                }
            })
        })
    }

    return <div>
        <input type="checkbox" checked={flag} onChange={() => checkAllHandler(!flag)} />全选
        <input type="checkbox" onChange={() => revCheckHandler()} />反选
        {list.map((item) => {
            return (<div key={item.id}>
                <input type="checkbox" onChange={() => singleChangeHandler(item.id, !item.state)} checked={item.state} value={item.hobby} />{item.hobby}
            </div>)
        })}
    </div>
}
export default CheckBox