React中点击按钮添加active类并移除前序点击按钮类的实现咨询
实现方案
核心调整逻辑
1. 互斥激活状态实现
原方案中每个按钮组件独立维护active状态,组件之间状态隔离无法实现互斥效果。我们需要把激活状态提升到公共父组件EntrieList中统一管理,仅存储当前激活的条目ID即可实现点击新按钮自动覆盖上一个激活状态的效果。
2. 右侧固定内容区实现
原方案中内容组件Entrie嵌套在每个按钮组件内部,自然会跟随对应按钮的高度位置渲染。我们把Entrie组件从按钮中抽离,统一放在右侧固定布局区域,仅渲染当前激活的条目内容,就能实现内容位置固定的需求。
修改后代码
EntrieList 组件(按钮列表父组件)
import React, { useState } from "react"; import EntrieButton from "./EntrieButton"; import Entrie from "./Entrie"; // 引入内容组件 const EntrieList = ({ entries, handleEditClick, handleDeleteClick }) => { const entrieCount = entries.length; // 新增:全局维护当前激活的条目ID,初始为null表示无选中 const [activeEntrieId, setActiveEntrieId] = useState(null); return ( <div className="container"> <h2> You have {entrieCount} {entrieCount === 1 ? `entrie` : `entries`} so far. </h2> {/* 外层用flex拆分左右两栏 */} <div className="flex h-screen bg-gray-100 mb-6 w-full"> {/* 左侧按钮滚动区 */} <div className="w-1/3 overflow-auto"> {entries.map((entrie) => ( <EntrieButton key={entrie.id} entrie={entrie} handleEditClick={handleEditClick} handleDeleteClick={handleDeleteClick} // 传递全局激活状态和修改方法 activeEntrieId={activeEntrieId} setActiveEntrieId={setActiveEntrieId} /> ))} </div> {/* 右侧内容固定展示区 */} <div className="w-2/3 h-full overflow-auto px-14 py-2 mt-2 mr-2 bg-white"> {/* 仅当有激活条目时渲染对应内容 */} {activeEntrieId && ( <Entrie entrie={entries.find(item => item.id === activeEntrieId)} onEditClick={handleEditClick} onDeleteClick={handleDeleteClick} /> )} </div> </div> </div> ); }; export default EntrieList;
EntrieButton 组件(单个按钮组件)
import React from "react"; const EntrieButton = ({ entrie, handleEditClick, handleDeleteClick, activeEntrieId, setActiveEntrieId }) => { // 用全局状态判断当前按钮是否激活 const isActive = activeEntrieId === entrie.id; const handleSetActive = (e) => { // 点击直接设置当前条目为激活状态,自动覆盖上一个激活项 setActiveEntrieId(entrie.id); }; return ( <div className="w-full bg-blue-300"> <button key={entrie.id} // 激活状态可自定义高亮样式,示例加了蓝色边框区分 className={`my-2 ml-2 rounded-sm shadow-sm overflow-hidden w-full ${isActive ? 'ring-2 ring-blue-600' : ''}`} onClick={handleSetActive} > <div className="flex justify-between w-full overflow-hidden"> <p className="bg-purple-300 w-1/4 px-2 py-4">{entrie.date}</p> <p className="bg-yellow-300 w-3/4 px-2 py-4">{entrie.heading}</p> </div> </button> </div> ); }; export default EntrieButton;
Entrie 组件(内容展示组件)
import React from "react"; const Entrie = ({ entrie, onEditClick, onDeleteClick }) => { return ( // 移除原来的浮动、显隐控制类,外层已有固定容器承接样式 <div className="h-full"> <p className="">{entrie.date}</p> <h2 className="text-2xl">{entrie.heading}</h2> <p>{entrie.mood}</p> <p>{entrie.text}</p> <div className="w-full flex justify-around py-8 border-t-2"> <button onClick={() => onEditClick(entrie)} className=""> <abbr title="Edit"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20px" > <path d="M12.3 3.7l4 4L4 20H0v-4L12.3 3.7zm1.4-1.4L16 0l4 4-2.3 2.3-4-4z" /> </svg> </abbr> </button> <button onClick={() => onDeleteClick(entrie.id)} className=""> <abbr title="Delete"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20px" > <path d="M6 2l2-2h4l2 2h4v2H2V2h4zM3 6h14l-1 14H4L3 6zm5 2v10h1V8H8zm3 0v10h1V8h-1z" /> </svg> </abbr> </button> </div> </div> ); }; export default Entrie;
最终效果
- 点击任意按钮自动切换激活状态,无需手动取消上一个按钮的选中
- 所有内容统一在右侧固定区域渲染,不会跟随左侧按钮的高度位置移动
- 支持动态增删条目,无需硬编码按钮和内容的对应关系
内容的提问来源于stack exchange,提问作者salia_in_red
相关产品推荐
相关产品推荐

