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

React中如何高效实现多手风琴展示不同内容?

高效实现React多手风琴组件的方案

结论:完全可以将不同手风琴拆分为独立组件(类组件或函数组件),同时通过通用组件复用逻辑,大幅简化代码。

下面提供两种落地方案:


方案一:通用手风琴容器 + 独立内容组件

先封装一个通用的手风琴容器组件,负责处理展开/收起的状态逻辑,将手风琴的标题和内部内容通过props传入。这样每个手风琴的表单内容可以拆成独立组件,复用容器的交互逻辑。

1. 通用手风琴容器(类组件版本)

import React, { Component } from 'react';

class Accordion extends Component {
  state = {
    isExpanded: false
  };

  toggleExpand = () => {
    this.setState(prevState => ({
      isExpanded: !prevState.isExpanded
    }));
  };

  render() {
    const { title } = this.props;
    const { isExpanded } = this.state;

    return (
      <div className="accordion-container">
        <div className="dropdown-header" onClick={this.toggleExpand}>
          <h4 className="dropdown-text">{title}</h4>
          <span className="dropdown-selection">{isExpanded ? '-' : '+'}</span>
        </div>
        {isExpanded && <div className="wrapper">{this.props.children}</div>}
      </div>
    );
  }
}

export default Accordion;

2. 独立的内容组件(比如配送信息表单)

import React from 'react';

const ShippingInfo = () => {
  return (
    <div className="row">
      <div className="col-md-6">
        <div className="info-group mb-3">
          <label>First name</label>
          <input type="text" className="info-input" name="firstname" />
        </div>
      </div>
      <div className="col-md-6">
        <div className="info-group mb-3">
          <label>Last name</label>
          <input type="text" className="info-input" name="lastname" />
        </div>
      </div>
      {/* 其他配送信息表单元素 */}
    </div>
  );
};

export default ShippingInfo;

3. 父组件中组合使用

import React from 'react';
import Accordion from './Accordion';
import ShippingInfo from './ShippingInfo';
import ShippingOptions from './ShippingOptions'; // 另一个手风琴内容组件

const CheckoutPage = () => {
  return (
    <div className="checkout-container">
      <Accordion title="Shipping Information">
        <ShippingInfo />
      </Accordion>
      <Accordion title="Shipping Options">
        <ShippingOptions />
      </Accordion>
    </div>
  );
};

export default CheckoutPage;

方案二:拆分独立的手风琴类组件

如果每个手风琴需要独立的状态管理或独特逻辑(比如配送选项需要处理选择后的联动),可以直接将每个手风琴写成独立的类组件:

示例:配送信息手风琴组件

import React, { Component } from 'react';

class ShippingInfoAccordion extends Component {
  state = {
    isExpanded: false,
    formData: {
      firstname: '',
      lastname: ''
    }
  };

  toggleExpand = () => {
    this.setState(prevState => ({
      isExpanded: !prevState.isExpanded
    }));
  };

  handleInputChange = (e) => {
    const { name, value } = e.target;
    this.setState(prevState => ({
      formData: {
        ...prevState.formData,
        [name]: value
      }
    }));
  };

  render() {
    const { isExpanded, formData } = this.state;

    return (
      <div className="accordion-container">
        <div className="dropdown-header" onClick={this.toggleExpand}>
          <h4 className="dropdown-text">Shipping Information</h4>
          <span className="dropdown-selection">{isExpanded ? '-' : '+'}</span>
        </div>
        {isExpanded && (
          <div className="wrapper">
            <div className="row">
              <div className="col-md-6">
                <div className="info-group mb-3">
                  <label>First name</label>
                  <input 
                    type="text" 
                    className="info-input" 
                    name="firstname" 
                    value={formData.firstname}
                    onChange={this.handleInputChange}
                  />
                </div>
              </div>
              <div className="col-md-6">
                <div className="info-group mb-3">
                  <label>Last name</label>
                  <input 
                    type="text" 
                    className="info-input" 
                    name="lastname" 
                    value={formData.lastname}
                    onChange={this.handleInputChange}
                  />
                </div>
              </div>
              {/* 其他表单元素 */}
            </div>
          </div>
        )}
      </div>
    );
  }
}

export default ShippingInfoAccordion;

父组件中直接使用

import React from 'react';
import ShippingInfoAccordion from './ShippingInfoAccordion';
import ShippingOptionsAccordion from './ShippingOptionsAccordion';

const CheckoutPage = () => {
  return (
    <div className="checkout-container">
      <ShippingInfoAccordion />
      <ShippingOptionsAccordion />
    </div>
  );
};

export default CheckoutPage;

额外优化:封装通用表单输入组件

如果表单元素重复较多,可以进一步封装通用Input组件,减少重复代码:

import React from 'react';

const FormInput = ({ label, name, value, onChange, type = 'text' }) => {
  return (
    <div className="info-group mb-3">
      <label>{label}</label>
      <input 
        type={type} 
        className="info-input" 
        name={name} 
        value={value}
        onChange={onChange}
      />
    </div>
  );
};

export default FormInput;

之后在内容组件中直接使用:

<FormInput 
  label="First name" 
  name="firstname" 
  value={formData.firstname} 
  onChange={this.handleInputChange}
/>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 22:05:24