Gatsby项目FAQ组件点击无展开效果求解决方案
FAQ点击展开功能故障修复

我正在开发一个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
相关产品推荐
相关产品推荐

