学生列表的实现

111 阅读1分钟
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            padding: 0;
            margin: 0;
        }

        html,
        body {
            width: 100%;
            height: 100%;
        }

        table {
            border-collapse: collapse;
            width: 100%;
        }

        th,
        td {
            border: 1px solid black;
            padding: 8px;
            text-align: center;
        }

        th {
            background-color: rgb(162, 162, 162);
        }

        .overlay {
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, .3);
            position: fixed;
            top: 0;
            left: 0;
        }

        .add_user_box {
            width: 350px;
            height: 130px;
            background-color: beige;
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            border-radius: 15px;
            padding: 20px;
        }

        .add_user_box input {
            width: 300px;
        }

        .btn_box {
            width: 100%;
            position: absolute;
            bottom: 30px;
            display: flex;
            justify-content: center;
        }

        .btn_box button {
            width: 100px;
            height: 30px;
        }

        .close {
            display: none;
        }
    </style>
</head>

<body>
    <button id="sort_btn">排序</button>
    <button id="add_btn">新增</button>
    <button id="get_age">获取平均年龄</button>
    <table></table>

    <!-- 遮罩层 -->
    <div class="overlay close"></div>

    <!-- 弹出层 -->
    <div class="add_user_box close">
        姓名: <input type="text" class="username">
        <br>
        年龄: <input type="text" class="userage">
        <br>
        城市: <input type="text" class="usercity">
        <br>
        <br>
        <div class="btn_box">
            <button class="close_box_btn">取消</button>
            <button class="add_user_btn">新增用户</button>
        </div>
    </div>

    <script>
        var data = JSON.parse(window.localStorage.getItem('data')) || [
            {
                status: true,
                id: 1,
                name: '张三',
                age: 25,
                city: '北京',
            },
            {
                status: false,
                id: 2,
                name: '李四',
                age: 30,
                city: '上海',
            },
            {
                status: true,
                id: 3,
                name: '王五',
                age: 22,
                city: '杭州',
            }
        ]

        // 页面打开时调用渲染函数
        bindHtml()

        // 创建一个渲染函数
        function bindHtml() {
            // 在页面渲染前, 先清空之前的页面
            document.querySelector('table').innerHTML = ""
            // 在页面渲染前, 先计算出有多少个数据被选中, 用于决定是否选中全选
            var checkedNum = 0  // 存储当前数据中 有多少个数据被选中了
            for (var q = 0; q < data.length; q++) {
                data[q].status && checkedNum++      // 如果当前对象的status属性为 true, 那么代表当前对象被选中了, 所以计数器 + 1
            }


            // ==================创建表头内容开始==================
            var headerArr = ['选择', '编号', '姓名', '年龄', '城市']
            var headerTr = document.createElement('tr')         // 当前tr只需要创建一个, 内部放一些 th 也就是 表头
            for (var j = 0; j < headerArr.length; j++) {        // 根据数据批量创建表头
                var headerTh = document.createElement('th')     // 创建一个表头
                if (j === 0) {                                  // 如果 j === 0, 代表循环第一次执行, 那么这个单元格的内容, 应该是一个多选框
                    var inp = document.createElement('input')   // 创建一个 input 标签, 注意: 默认为 输入框
                    inp.type = 'checkbox'                       // 如果没有这一行那么创建的默认是一个 单行文本输入框
                    inp.className = 'check_all'                 // 因为一会需要添加事件, 所以这里提前给这个选择框添加一个类名标识
                    inp.checked = checkedNum === data.length    // 根据 现有选中的数据数量和总数据数量对比, 如果相同代表所有数据被选中, 那么选中全选按钮
                    headerTh.appendChild(inp)                   // 将 多选框 添加到 th 中
                } else {
                    headerTh.innerHTML = headerArr[j]           // 给表头单元格赋值一个文本
                }
                headerTr.appendChild(headerTh)                  // 将 th 单元格 放到 tr 单元行 内
            }
            document.querySelector('table').appendChild(headerTr)
            // ==================创建表头内容结束==================


            // ==================创建表格内容开始==================
            for (var i = 0; i < data.length; i++) {
                var myTr = document.createElement('tr')
                var dataKeys = Object.keys(data[i])
                for (var k = 0; k < dataKeys.length; k++) {
                    var myTd = document.createElement('td')
                    // 如果 展示的内容是一个 布尔值, 那么应该展示一个多选框
                    if (data[i][dataKeys[k]] === true || data[i][dataKeys[k]] === false) {
                        var inpItems = document.createElement('input')  // 创建一个 input 标签, 注意: 默认为单行输入框
                        inpItems.type = 'checkbox'                      // 更改类型为 多选框
                        inpItems.className = 'check_item'               // 给多选框添加类名, 因为一会需要添加事件
                        inpItems.checked = data[i][dataKeys[k]]         // 给多选框 添加一个默认的选中状态, 需要根据数据提供的来展示
                        inpItems.dataset.id = i + 1                     // 用于给 标签 添加一个 标识, 能够知道将来点的是那个
                        myTd.appendChild(inpItems)
                        // 将 多选框 添加到 td 单元格中
                    } else {
                        myTd.innerText = data[i][dataKeys[k]]           // 如果 展示的内容不是 布尔值, 那么正常展示文本
                    }
                    myTr.appendChild(myTd)
                }




                document.querySelector('table').appendChild(myTr)
            }
            // ==================创建表格内容结束==================

            // ==================持久化数据==================
            window.localStorage.setItem('data', JSON.stringify(data))
        }



        // ==================全选功能 (事件委托) 开始==================
        var myTable = document.querySelector('table')
        myTable.onclick = function (e) {
            if (e.target.className === 'check_all') {
                // 1. 修改数据
                for (var i = 0; i < data.length; i++) {
                    data[i].status = e.target.checked
                }

                // 2. 重新渲染页面
                bindHtml()
            }
            if (e.target.className === 'check_item') {
                // 1. 修改数据
                for (var k = 0; k < data.length; k++) {
                    if (e.target.dataset.id - 0 === data[k].id) {
                        data[k].status = e.target.checked
                    }
                }

                // 2. 重新渲染页面
                bindHtml()
            }
        }
        // ==================全选功能 (事件委托) 结束==================

        // ==================排序功能开始==================
        var sortBtn = document.querySelector('#sort_btn')
        var num = 0
        sortBtn.onclick = function () {
            num++   // 每次点击的时候 修改计数器的数字
            if (num === 1) { // 1. 第一次点击 按照 年龄的从小到大
                data.sort(function (a, b) { return a.age - b.age })
            } else if (num === 2) { // 2. 第二次点击 按照 年龄的从大到小
                data.sort(function (a, b) { return b.age - a.age })
            } else { // 3. 第三次点击 恢复默认排序(按照ID从小到大)
                data.sort(function (a, b) { return a.id - b.id })
                num = 0 // 清零计数器, 下次可以重新执行逻辑
            }
            // 上述的 if 语句内 处理完数据后, 重新渲染页面
            bindHtml()
        }
        // ==================排序功能结束==================

        // ==================新增功能开始==================
        // 1. 点击 "新增按钮" 打开 遮罩层 和 信息框
        var addBtn = document.querySelector('#add_btn')
        var overlay = document.querySelector('.overlay')
        var addUserBox = document.querySelector('.add_user_box')
        addBtn.onclick = function () {
            overlay.classList.remove('close')
            addUserBox.classList.remove('close')
        }
        // 2. 点击 "新增用户按钮" 收集用户输入的信息, 然后创建一个对象, 追加到原数组的末尾, 最后重新渲染页面
        var addUserBtn = document.querySelector('.add_user_btn')
        addUserBtn.onclick = function () {
            // 2.1 获取到用户输入的信息
            var nameEl = document.querySelector('.username')
            var ageEl = document.querySelector('.userage')
            var cityEl = document.querySelector('.usercity')

            var nameValue = nameEl.value
            var ageValue = ageEl.value
            var cityValue = cityEl.value

            // 2.2 安全校验 (非空校验, 规则校验/正则校验)
            if (nameValue === '' || ageValue === '' || cityValue === '') return alert('您的输入框有一个为空, 请补全输入框')

            // 2.3 如果代码能够正常执行到这里, 说明输入框的的内容不是空的, 所以可以组装一个对象, 然后追加到原数组的末尾
            var obj = {
                status: false,
                id: data.length + 1,
                name: nameValue,
                age: ageValue - 0,
                city: cityValue,
            }
            data.push(obj)

            // 2.4 调用渲染函数
            bindHtml()

            // 2.5 清空弹框数据
            nameEl.value = ''
            ageEl.value = ''
            cityEl.value = ''

            // 2.6 关闭弹框
            closeBoxFn()
        }
        // 3. 点击 "取消按钮" 关闭 遮罩层和信息框
        var closeBoxBtn = document.querySelector('.close_box_btn')
        closeBoxBtn.onclick = closeBoxFn
        function closeBoxFn() {
            overlay.classList.add('close')
            addUserBox.classList.add('close')
        }
        // ==================新增功能结束==================


        // ==================获取平均年龄开始==================
        var getAge = document.querySelector('#get_age')
        getAge.onclick = function () {
            // 1. 获取到年龄的总和
            var sum = 0
            for (var i = 0; i < data.length; i++) {
                sum += data[i].age
            }

            // 2. 总和 / 总数量 === 年龄的平均值
            sum = sum / data.length

            // 3. 提示给用户年龄的平均值
            alert(sum.toFixed(1))
        }
        // ==================获取平均年龄结束==================
    </script>
</body>

</html>
    ```