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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 07:24:00