表格框选功能(模仿钉钉划线排班功能)

在这里插入图片描述
需求: 开发一个类似的框选表格去排班的功能
备注: 因为是帮助别人评估的,之前没接触过类似的功能,所以只做了简易的前端功能,暂未涉及后端
重点: 表格 框选 排班(类似excel选中多个表格)、日历的查询
分析: 初始以为日历的查询有封装好的库百度了一下发现还是得通过new Date()去实现、表格的框选一开始是想着通过坐标的方式去范围覆盖,但是实施起来比较困难,百度了也没有啥示例,有一个示例也是通过坐标的,代码比较复杂,不易理解
思路: 类似坐标,通过数组的方式来确定选中的范围
例如 选择的坐标是:1-17,4-18,则选中的内容就是第一行的17、18列到第四行的17、18列

效果:
在这里插入图片描述
在这里插入图片描述
补充微调了表格样式
在这里插入图片描述

import React, { useState, useEffect } from 'react';
import { DatePicker } from 'antd';
import dayjs from 'dayjs';
import customParseFormat from 'dayjs/plugin/customParseFormat';
dayjs.extend(customParseFormat);

const monthFormat = 'YYYY-MM';

export default function CuxTable() {
    const [startCellId, setStartCellId] = useState('');
    const [endCellId, setEndCellId] = useState('');
    const [dateMonth, setDateMonth] = useState('2024-03');
    const [daysList, setDaysList] = useState([]);

    // 根据起始和结束的坐标来处理数据
    const handleCellData = () => {
        // 按照坐标思维
        // 鼠标摁下的单元格的行列
        const startRow = +startCellId.split('-')[0];
        const startCol = +startCellId.split('-')[1];
        // 鼠标松开的单元格的行列
        const endRow = +endCellId.split('-')[0];
        const endCol = +endCellId.split('-')[1];
        // 选中单元格id
        const selectedCellList = [];
        // 双重遍历
        // 行遍历
        for (let i = startRow; i <= endRow; i++) {
            for (let j = startCol; j <= endCol; j++) {
                selectedCellList.push(`${i}-${j}`)
            }
        }
        const alertTextList = [];
        selectedCellList.forEach(item => {
            document.getElementById(item).style.backgroundColor = 'red'
            // 这里可以对选中的数据进行赋值之类的
            // document.getElementById(item).innerHTML = '1';
            alertTextList.push(document.getElementById(item).outerText)
        })
        setTimeout(() => {
            alert(`选择的日期:   ${alertTextList}`)
        }, 100);
        setStartCellId('')
        setEndCellId('')
    }

    const setFun = () => {
        // 获取你想要添加鼠标按下事件的元素
        const elements = document.getElementsByTagName('td');
        // 定义鼠标按下事件的处理函数
        function handleMousedown(event) {
            // 这里可以添加你想要执行的代码
            setStartCellId(event.target.id)
        }
        // 定义鼠标松开事件的处理函数
        function handleMouseup(event) {
            // 这里可以添加你想要执行的代码
            setEndCellId(event.target.id)
        }
        // 为元素添加鼠标按下事件的监听器
        Array.from(elements).forEach(item => {
            item.style.userSelect = 'none';
            item.addEventListener('mousedown', handleMousedown);
            item.addEventListener('mouseup', handleMouseup);
        })
    }
    const getDaysInMonthWithWeekdays = (year, month) => {
        const daysInMonth = new Date(year, month, 0).getDate(); // 获取该月有多少天
        const weekdays = []; // 用于存储每一天的数组
        for (let day = 1; day <= daysInMonth; day++) {
            const date = new Date(year, month, day);
            const weekday = date.getDay(); // 获取是星期几,返回0(代表星期日)到6(代表星期六)
            weekdays.push({ date: day, weekday: weekday });
        }
        return weekdays;
    }

    const onChange = (date, dateString) => {
        // console.log(date, dateString);
        let year = dateString.split('-')[0]
        let month = dateString.split('-')[1]
        const monthDaysWithWeekdays = getDaysInMonthWithWeekdays(year, month);
        const dayWithWeekdayList = [];
        monthDaysWithWeekdays.forEach(day => {
            const dayOfWeek = ['日', '一', '二', '三', '四', '五', '六'][day.weekday];
            const dayWithWeekday = `${day.date}-${dayOfWeek}`;
            dayWithWeekdayList.push(dayWithWeekday)
            console.log(`${day.date} is a ${dayOfWeek}`);

        });
        setDaysList(dayWithWeekdayList);
    };

    useEffect(() => {
        setTimeout(() => {
            setFun();
        }, 1000);
    }, []);

    useEffect(() => {
        if (startCellId && endCellId) {
            handleCellData();
        }
        onChange('', dateMonth);
    }, [startCellId, endCellId])

    const renderDayTh = () => {
        const dayTh = [];
        const name = <th style={{ borderBottom: 'none' }} rowSpan={2}>姓名</th>;
        dayTh.push(name);
        if (daysList.length) {
            daysList.forEach(item => {
                dayTh.push(<th style={{ borderBottom: 'none' }}>{item.split('-')[0]}</th>)
            })
        }
        return dayTh
    }
    const renderWeekTh = () => {
        const weekTh = [];
        if (daysList.length) {
            daysList.forEach(item => {
                weekTh.push(<th style={{ borderTop: 'none' }}>{item.split('-')[1]}</th>)
            })
        }
        return weekTh;
    }

    // 人员的姓名
    const userList = ['白一', '紫二', '金三', '黄四', '赤五'];

    const renderTd = (item, index) => {
        const tdList = [];
        const name = <td>{item}</td>;
        tdList.push(name);
        if (daysList.length) {
            daysList.forEach((day, dayIndex) => {
                tdList.push(<td id={`${index + 1}-${dayIndex + 1}`} >{`${index + 1}-${dayIndex + 1}`}</td>)
            })
        }
        return tdList;
    }

    const renderTbody = () => {
        const tbodyList = [];
        userList.forEach((item, index) => {
            // const nameList = [];
            const tdList = renderTd(item, index);
            const nametbody = <tr>
                {
                    tdList
                }
            </tr>;
            tbodyList.push(nametbody);
        })
        return tbodyList;
    }

    console.log(123, startCellId, endCellId);

    return (
        <div style={{ margin: 10 }}>
            <DatePicker defaultValue={dayjs(dateMonth, monthFormat)} format={monthFormat} onChange={onChange} picker="month" />
            <table width="100%" border="1" cellspacing="0" cellpadding="4" style={{ marginTop: '10px' }} align="center">
                <tr >
                    {daysList.length > 0 && renderDayTh()}
                </tr>
                <tr >
                    {daysList.length > 0 && renderWeekTh()}
                </tr>
                {daysList.length > 0 && renderTbody()}
            </table>
        </div>
    );
}

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值