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,所有绑定该条件的预览框都会被渲染。要实现单个按钮的独立预览,需要把状态改为记录当前被悬停的唯一标识(比如课程名称),而非单纯的布尔值。
具体修改步骤:
- 修改状态定义:将布尔值状态改为存储当前悬停的课程(初始值设为
null)
// 替换原来的const [preview, setPreview] = useState(false); const [previewCourse, setPreviewCourse] = useState(null);
- 更新鼠标事件逻辑:在
onMouseEnter时传入当前课程作为标识,onMouseLeave时清空标识
<button value={subject} className="course_btn" onMouseEnter={() => setPreviewCourse(course)} onMouseLeave={() => setPreviewCourse(null)}> {course} </button>
- 调整预览框显示条件:只有当
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
相关产品推荐
相关产品推荐

