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

React动态生成表格:实现单行悬浮弹窗的方法问询

解决React表格悬停行弹窗全局显示问题

你的问题核心是用单一状态控制所有行的弹窗显示,导致悬停任意一行时所有弹窗都会触发。下面是具体的修复方案:

关键改动点

  • 用状态存储当前悬停的预约唯一标识(比如appointmentId或数组索引),而非全局布尔值
  • 修复表格的非法嵌套结构(<tr>内不能直接放<div>)
  • 给鼠标事件传递当前预约的标识,精准控制弹窗显示

完整修复代码

import { useState, useEffect, Fragment } from 'react';

function ScheduleComponent(props) {
    // 存储当前悬停的预约ID(或索引,根据你的数据结构选择)
    const [hoveredAppointmentId, setHoveredAppointmentId] = useState(null);
    const [schedule, setSchedule] = useState([]);

    useEffect(() => {
        setSchedule(props.schedule);
    }, [props.schedule]);

    // 鼠标悬停时记录当前预约的ID
    const handleMouseOver = (appointmentId) => {
        setHoveredAppointmentId(appointmentId);
    };

    // 鼠标离开时清空记录
    const handleMouseOut = () => {
        setHoveredAppointmentId(null);
    };

    const showAppointments = schedule.map((appointment, i) => {
        const hasAppointment = appointment.appointmentDto != null;
        // 用appointmentDto的id作为唯一标识,如果没有id可以用索引i
        const appointmentId = hasAppointment ? appointment.appointmentDto.id : null;

        return (
            <Fragment key={i}>
                <tr 
                    // 把事件绑定到整行,体验更友好
                    onMouseOver={() => hasAppointment && handleMouseOver(appointmentId)} 
                    onMouseOut={handleMouseOut}
                >
                    <td>{appointment.hourOfService}</td>
                    <td>
                        {hasAppointment ? appointment.appointmentDto.name : "No hay citas programadas"}
                    </td>
                </tr>
                {/* 只有当前悬停的预约匹配时,才渲染弹窗 */}
                {hasAppointment && hoveredAppointmentId === appointmentId && (
                    <tr>
                        {/* 合并两列显示弹窗内容 */}
                        <td colSpan="2" style={{ backgroundColor: "#f5f5f5", padding: "10px", borderTop: "1px solid #eee" }}>
                            <h4>额外预约信息</h4>
                            <p>客户姓名:{appointment.appointmentDto.name}</p>
                            <p>预约项目:{appointment.appointmentDto.serviceType}</p>
                            {/* 这里添加你需要展示的其他额外字段 */}
                        </td>
                    </tr>
                )}
            </Fragment>
        );
    });

    return (
        <div>
            <table style={{ borderCollapse: "collapse", width: "100%" }}>
                <thead>
                    <tr style={{ borderBottom: "2px solid #ddd" }}>
                        <th style={{ padding: "8px", textAlign: "left" }}>Hora</th>
                        <th style={{ padding: "8px", textAlign: "left" }}>Descripcion</th>
                    </tr>
                </thead>
                <tbody>
                    {showAppointments}
                </tbody>
            </table>
        </div>
    );
}

export default ScheduleComponent;

代码说明

  1. 状态管理:hoveredAppointmentId只存储当前悬停的预约ID,确保只有对应行的弹窗会显示
  2. 表格结构修复:移除了<tr>内的非法<div>嵌套,用Fragment包裹多行,符合HTML表格规范
  3. 事件优化:把鼠标事件绑定到整行,用户体验更自然;只有存在预约的行才会触发悬停逻辑
  4. 弹窗渲染:用colSpan="2"合并列展示弹窗内容,确保表格布局正常,同时添加基础样式提升可读性

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 10:40:59