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

Gatsby项目FAQ组件点击无展开效果求解决方案

FAQ点击展开功能故障修复

Console logs

我正在开发一个Gatsby项目,尝试实现点击FAQ问题时滑出展示答案的功能。尽管控制台已打印容器被点击的日志,但答案始终处于隐藏状态。

JavaScript代码(原代码)

import React, { useEffect, useState } from "react";
import axios from 'axios'
import * as styles from './style-modules/faq.module.css'
import { Container } from 'react-bootstrap';


const Faq = () => {
  const [faqs, setFaqs] = useState([])

  useEffect(() => {
    const fetchData = async () => {
      console.log("Fetching data...")
      try {
        const result = await axios.get("http://127.0.0.1:8000/faq")
        console.log("Data fetched successfully:", result.data)
        setFaqs(result.data)
      } catch (error) {
        console.error("Error fetching data:", error)
      }
    }

    fetchData()

}, []);

    useEffect(() => {
      const faqButtons = document.querySelectorAll(`.${styles.questions}`)
      console.log(faqButtons)

      const answersContainers = document.querySelectorAll(`.${styles.answers}`);

      faqButtons.forEach((faqButton, index) => {
        const answersContainer = answersContainers[index];

        const computedStyle = window.getComputedStyle(answersContainer);
        const maxHeight = computedStyle.getPropertyValue('max-height');
        console.log(maxHeight);

        if (faqButton == null || faqButton < 0) {
          console.log("No content in container")
        } else {
          console.log("Selecting Container...")
          faqButton.addEventListener("click", () => {
            console.log("Container was clicked!")
            answersContainer.classList.toggle("open");
            console.log("Container was open!")
            console.log(maxHeight)
          });
        }
      });
    }, [faqs]);

    return (
      <Container>
        {faqs?.map(faq => (
          <div key={faq.questions} className={styles.faq}>
            <div className={styles.questions} >
              <h4>{faq.questions}</h4>
            </div>
            <div className={styles.answers}>
              <p>{faq.answers}</p>
            </div>
          </div>
        ))}
      </Container>
    );
};

export default Faq;

CSS代码(原代码)

.faq_section {
    display: flex;
    justify-content: center;
    flex-direction: column;
    padding: 20px;
}


.faq {
    box-sizing: border-box;
    display: flex;
    align-items: left;
    padding-left: 10px;
    padding-right: 10px;
    flex-direction: column;
}

.questions {
    /* font-size: 5vmin; */
    border: none;
    background-color: transparent;
    box-sizing: border-box;
    display: flex;
    align-items: center;
    cursor: pointer;
    height: auto;
    padding: 15px;
    border-bottom: 1px solid rgb(184, 184, 184)
}

.questions.active {
    background-color: rgb(207, 233, 237);
}

.questions:hover {
    background-color: rgb(207, 233, 237);
    transition: background-color 0.2s ease-in;
}

.answers {
    max-height: 0;
    overflow: hidden;
    transition: max-height 0.2s ease-out;
}

  .answer.open {
    height: 1000px;
  }

问题分析与修复方案

1. 修复CSS类名与样式逻辑

原CSS存在两个核心问题:

  • 类名错误:目标容器是.answers,但写的是.answer.open,少了末尾的s;
  • 属性错误:初始用max-height: 0隐藏内容、过渡效果基于max-height,但展开时设置的是height,无法触发过渡且逻辑不匹配。

修改后的CSS相关片段:

.answers {
    max-height: 0;
    overflow: hidden;
    transition: max-height 0.2s ease-out;
}

.answers.open {
    max-height: 1000px; /* 设置足够容纳所有答案内容的高度 */
}

2. 改用React状态管理替代原生DOM操作

原代码用原生DOM绑定事件的方式不符合React设计思路,会导致重复绑定(每次faqs更新都会重新添加事件,一次点击触发多次回调)。建议用React状态管理每个FAQ的展开状态:

优化后的完整组件代码:

import React, { useEffect, useState } from "react";
import axios from 'axios'
import * as styles from './style-modules/faq.module.css'
import { Container } from 'react-bootstrap';

const Faq = () => {
  const [faqs, setFaqs] = useState([]);
  // 用对象存储每个FAQ的展开状态,以问题内容为唯一key
  const [openStates, setOpenStates] = useState({});

  useEffect(() => {
    const fetchData = async () => {
      console.log("Fetching data...");
      try {
        const result = await axios.get("http://127.0.0.1:8000/faq");
        console.log("Data fetched successfully:", result.data);
        setFaqs(result.data);
        // 初始化所有FAQ为关闭状态
        const initialStates = result.data.reduce((acc, faq) => {
          acc[faq.questions] = false;
          return acc;
        }, {});
        setOpenStates(initialStates);
      } catch (error) {
        console.error("Error fetching data:", error);
      }
    };

    fetchData();
  }, []);

  // 切换指定FAQ的展开状态
  const toggleAnswer = (question) => {
    setOpenStates(prevState => ({
      ...prevState,
      [question]: !prevState[question]
    }));
  };

  return (
    <Container>
      {faqs?.map(faq => (
        <div key={faq.questions} className={styles.faq}>
          <div 
            className={styles.questions}
            onClick={() => toggleAnswer(faq.questions)}
          >
            <h4>{faq.questions}</h4>
          </div>
          {/* 根据状态动态添加open类 */}
          <div 
            className={`${styles.answers} ${openStates[faq.questions] ? 'open' : ''}`}
          >
            <p>{faq.answers}</p>
          </div>
        </div>
      ))}
    </Container>
  );
};

export default Faq;

3. 原代码其他问题说明

  • 点击事件中打印的maxHeight是组件挂载时的初始值(0),不会随状态更新,无实际调试价值;
  • 原生DOM事件绑定会在faqs更新时重复执行,导致同一元素绑定多个点击事件,引发多次触发问题,用React状态管理可彻底避免此类问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 07:35:20