You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React自定义日视图调度器轮播失效,请求代码排查

问题描述

我正在尝试实现一个React自定义日视图调度器轮播,但当前功能无法正常运行。点击上一页或下一页按钮时无任何响应,虽然打印refs显示其已正常更新,但滚动逻辑似乎未生效。请问这段代码存在什么问题,导致无法达到预期效果?我哪里操作出错了?我仅希望点击前后按钮时,refs能相应触发滚动逻辑。

原代码
const DailyTable = () => {
  let time = [
    "12:00 AM",
    "01:00 AM",
    "02:00 AM",
    "03:00 AM",
    "04:00 AM",
    "05:00 AM",
    "06:00 AM",
    "07:00 AM",
    "08:00 AM",
    "09:00 AM",
    "10:00 AM",
    "11:00 AM",
    "12:00 PM",
    "01:00 PM",
    "02:00 PM",
    "03:00 PM",
    "04:00 PM",
    "05:00 PM",
    "06:00 PM",
    "07:00 PM",
    "08:00 PM",
    "09:00 PM",
    "10:00 PM",
    "11:00 PM",
  ];

  const boxRef = useRef(null);
  const boxRef2 = useRef([]);
  const addToRef = (el) => {
    boxRef2.current = [];
    if (boxRef2 && !boxRef2.current.includes(el)) {
      boxRef2.current.push(el);
    }
  };
  const previous = () => {
    boxRef.current.scrollLeft += -100;
    for (let index = 0; index < boxRef2.current.length; index++) {
     boxRef2.current[index].scrollLeft += -100;
    
    }
  };
  const next = () => {
    console.log(boxRef2.current.length);
    boxRef.current.scrollLeft += 100;
    for (let index = 0; index < boxRef2.current.length; index++) {
      console.log(boxRef2.current[index]);
      boxRef2.current[index].scrollLeft += 100;
    }
  };

  return (
    <Fragment>
      <Box sx={{ p: 3, borderRadius: "10px" }}>
        <TableContainer
          component={Paper}
          sx={{
            width: "calc(100% - 20px)",
            overflow: "hidden",
            borderBottomLeftRadius: 15,
            bottom: 0,
          }}
        >
            <Table>
              <TableHead>
                <TableRow>
                  <TableCell
                    align="center"
                    sx={{ width: "150px", fontWeight: 700 }}
                  >
                    Worker
                  </TableCell>
                  <Box
                    sx={{
                      position: "relative",
                      display: "flex",
                      alignItems: "center",
                      borderBottom: "1px solid rgba(224, 224, 224, 1)",
                    }}
                  >
                    <span
                      style={{ cursor: "pointer", marginTop: 7 }}
                      onClick={previous}
                    >
                      {" "}
                      <FaArrowLeft />
                    </span>
                    <Box
                      ref={boxRef}
                      sx={{ width: "calc(100% - 20px)", overflow: "hidden" }}
                    >
                      {time.map((item, index) => {
                        return (
                          <TableCell
                            key={index}
                            id={index}
                            sx={{ minWidth: 20, borderBottom: "none" }}
                          >
                            {item}
                          </TableCell>
                        );
                      })}
                    </Box>
                    <span
                      style={{
                        marginTop: 7,
                        cursor: "pointer",
                        position: "absolute",
                        right: 10,
                      }}
                      onClick={next}
                    >
                      {" "}
                      <FaArrowRight />
                    </span>
                  </Box>
                </TableRow>
              </TableHead>
              {workers.map((item, index) => {
                return (
                  <TableBody>
                    <Box
                      ref={addToRef}
                      sx={{
                        width: "calc(100% - 20px)",
                        overflow: "hidden",
                        position: "relative",
                        top: 1,
                      }}
                    >
                      {time.map((timeV, index) => {
                        return (
                          <TableCell
                            key={index}
                            id={index}
                            align="left"
                            sx={{
                              verticalAlign: "middle",
                              height: 77,
                              minWidth: 100,
                              p: 0.7,
                              borderRight: "1px solid rgba(224,224,224,1)",
                            }}
                          >
                            {item.assignWorks.map((work, index) => {
                              var mStart = moment(work.assignDetails.startTime);
                              var roundUpStartTime =
                                mStart.minute() ||
                                mStart.second() ||
                                mStart.millisecond()
                                  ? mStart.add(1, "hour").startOf("hour")
                                  : mStart.startOf("hour");
                              var width =
                                work.assignDetails.timeDiff == 0
                                  ? 106
                                  : work.assignDetails.timeDiff * 106;
                              let count = 0;
                              if (
                                roundUpStartTime.format("hh:mm A") === timeV
                              ) {
                                count += 1;
                                return (
                                  <Box key={index}>
                                    {(work.assignDetails.status === "pending" ||
                                      work.assignDetails.status ===
                                        "request") && (
                                      <Chip
                                      onClick={() => {
                                        setSelectedJob(work._id);
                                        setShowEditJob(true);
                                      }}
                                        label={work.name}
                                        sx={{
                                          mb: 2,
                                          borderRadius: "5px",
                                          fontWeight: 600,
                                          backgroundColor: `${colors.chip.lightBlue}`,
                                          color: `${colors.chip.Blue}`,
                                          width: width - 12,
                                        }}
                                      />
                                    )}
                                  </Box>
                                )
                              }
                            })}
                          </TableCell>
                        );
                      })}
                    </Box>
                  </TableBody>
                );
              })}
            </Table>
        </TableContainer>
      </Box>
    </Fragment>
  );
};
问题分析与解决方案

1. Ref收集逻辑错误

addToRef函数每次调用都会清空boxRef2.current = [],导致最终boxRef2.current中只会保留最后一个worker对应的Box元素,前面的所有ref都会丢失。修改方式:

const addToRef = (el) => {
  if (el && !boxRef2.current.includes(el)) {
    boxRef2.current.push(el);
  }
};
// 组件卸载时清理ref,避免内存泄漏
useEffect(() => {
  return () => {
    boxRef2.current = [];
  };
}, []);

2. 滚动容器样式错误

所有需要滚动的容器设置了overflow: hidden,这会阻止容器滚动,必须改为overflow-x: scroll(只允许水平滚动):

// 表头的滚动容器
<Box
  ref={boxRef}
  sx={{ width: "calc(100% - 20px)", overflowX: "scroll" }}
>
  {/* 时间列内容 */}
</Box>

// 每个worker的滚动容器
<Box
  ref={addToRef}
  sx={{
    width: "calc(100% - 20px)",
    overflowX: "scroll",
    position: "relative",
    top: 1,
  }}
>
  {/* 任务列内容 */}
</Box>

3. Table结构不符合规范

在workers.map中直接返回<TableBody>违反了Table组件的结构规范:一个<Table>应包含一个<TableBody>,且<TableRow>的子元素必须是<TableCell>。正确结构调整如下:

<Table>
  <TableHead>
    {/* 原有表头代码 */}
  </TableHead>
  <TableBody>
    {workers.map((item, index) => {
      return (
        <TableRow key={index}>
          <TableCell align="center" sx={{ width: "150px" }}>
            {item.name} {/* 显示worker名称 */}
          </TableCell>
          <TableCell sx={{ p: 0 }}>
            <Box
              ref={addToRef}
              sx={{
                width: "100%",
                overflowX: "scroll",
              }}
            >
              {/* 原有时间列与任务内容 */}
            </Box>
          </TableCell>
        </TableRow>
      );
    })}
  </TableBody>
</Table>

4. Moment对象可变问题

直接修改moment原对象会导致时间计算异常,需要先克隆对象:

var mStart = moment(work.assignDetails.startTime).clone();
var roundUpStartTime =
  mStart.minute() || mStart.second() || mStart.millisecond()
    ? mStart.add(1, "hour").startOf("hour")
    : mStart.startOf("hour");

内容的提问来源于stack exchange,提问作者Muhammad Abdullah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 01:10:29