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

React中map生成的按钮实现单独Hover显示预览框问题求助

问题:如何实现仅让被悬停的按钮显示对应的预览框?

我通过map函数渲染了一组按钮,期望鼠标悬停在某个按钮上时,其侧边显示一个黑色预览框(后续将扩展为完整预览内容)。但当前存在问题:由于使用了map函数,悬停单个按钮时,所有按钮的预览框都会被显示;鼠标移出按钮后,所有预览框又都会消失。按钮按学科分组展示,学科与课程均通过map函数渲染。

相关代码如下:

export default function Yeartwo() {
  const [grade, setGrade] = useState(localStorage.getItem('grade'));
  const [preview, setPreview] = useState(false);
  let grades = Object.keys(courseData)
  let nextGrade = grades[Object.keys(courseData).indexOf(grade)+1]
  let subjects = courseData[nextGrade].subjects
  let courses = courseData[nextGrade].classes

function coursePreview(e) { 
  e.preventDefault();
  console.log('hovered')
  setPreview(true)
}

    return (
        <div className="courseSelect">

          {subjects.map((subject, index) => (

            <div key={index}>
              <h2 className="subject">{subject}</h2>
              <div className="courses">

              {courses[subject].map((course, index) => (

                <div key={index}>
                    <button value={subject} className="course_btn" onMouseEnter={() => setPreview(true)} onMouseLeave={() => setPreview(false)}>{course}</button>
                    {preview && <div className="preview"> {course} </div>}

                </div>
              ))}
              </div>
            </div>
          ))}
        </div>

  )
}

解决方案

问题根源在于你用了一个全局布尔状态preview控制所有预览框的显示,只要这个状态变为true,所有绑定该条件的预览框都会被渲染。要实现单个按钮的独立预览,需要把状态改为记录当前被悬停的唯一标识(比如课程名称),而非单纯的布尔值。

具体修改步骤:

  1. 修改状态定义:将布尔值状态改为存储当前悬停的课程(初始值设为null)
// 替换原来的const [preview, setPreview] = useState(false);
const [previewCourse, setPreviewCourse] = useState(null);
  1. 更新鼠标事件逻辑:在onMouseEnter时传入当前课程作为标识,onMouseLeave时清空标识
<button value={subject} className="course_btn" 
        onMouseEnter={() => setPreviewCourse(course)} 
        onMouseLeave={() => setPreviewCourse(null)}>
  {course}
</button>
  1. 调整预览框显示条件:只有当previewCourse等于当前遍历的课程时,才显示对应的预览框
{previewCourse === course && <div className="preview"> {course} </div>}

修改后的完整代码:

export default function Yeartwo() {
  const [grade, setGrade] = useState(localStorage.getItem('grade'));
  // 改为存储当前悬停的课程
  const [previewCourse, setPreviewCourse] = useState(null);
  let grades = Object.keys(courseData)
  let nextGrade = grades[Object.keys(courseData).indexOf(grade)+1]
  let subjects = courseData[nextGrade].subjects
  let courses = courseData[nextGrade].classes

  return (
    <div className="courseSelect">
      {subjects.map((subject, index) => (
        <div key={index}>
          <h2 className="subject">{subject}</h2>
          <div className="courses">
            {courses[subject].map((course, index) => (
              <div key={index}>
                <button 
                  value={subject} 
                  className="course_btn" 
                  onMouseEnter={() => setPreviewCourse(course)} 
                  onMouseLeave={() => setPreviewCourse(null)}
                >
                  {course}
                </button>
                {/* 仅当当前课程是悬停的课程时显示预览框 */}
                {previewCourse === course && <div className="preview"> {course} </div>}
              </div>
            ))}
          </div>
        </div>
      ))}
    </div>
  )
}

如果课程名称可能重复,建议给每个课程添加唯一ID,用ID作为标识来判断,避免出现多个相同名称课程同时显示预览的问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 20:30:42