React + TypeScript 手风琴过渡动画失效问题求助
React + TypeScript 手风琴组件过渡动画失效问题
问题详情
自定义手风琴组件时,展开/收起的内容过渡动画、图标切换动画均不生效,添加通用过渡样式后仍无改善。
相关代码
index.tsx
import { useState } from "react"; import { AccordionButton, AccordionContent, Wrapper } from "./styles"; import { AccordionProps } from "./interfaces"; import { BsChevronDown, BsChevronUp } from "react-icons/bs"; export default function Accordion({ title, text }: AccordionProps) { const [isOpen, setIsOpen] = useState(false); const handleClick = () => { setIsOpen(!isOpen); returnIcon(); }; const returnIcon = () => { return isOpen ? <BsChevronUp /> : <BsChevronDown />; }; return ( <Wrapper> <AccordionButton onClick={handleClick}> {title} {returnIcon()} </AccordionButton> <AccordionContent isOpen={isOpen}> <p>{text}</p> </AccordionContent> </Wrapper> ); }
styled-components 样式代码
import styled from "styled-components"; import { AccordionContentProps } from "./interfaces"; export const AccordionButton = styled.button` background-color: #606582; color: #ffffff; cursor: pointer; padding: 18px; width: 100%; border: none; text-align: left; outline: none; font-size: 15px; transition: 0.6s; &:hover { background-color: #60658295; } > svg { float: right; } `; export const AccordionContent = styled.div<AccordionContentProps>` display: ${(props) => (props.isOpen === false ? "none" : "block")}; padding: 0 18px; background-color: white; overflow: hidden; `; export const Content = styled.div` padding: 10px 0px; flex-wrap: wrap; max-width: 750px; margin-right: auto; margin-left: auto; @media only screen and (max-width: 600px) { max-width: 80%; } `; export const Wrapper = styled.div` padding: 10px 0px; `;
已尝试无效操作
添加以下过渡样式后问题未解决:
-webkit-transition: all 0.4s ease-in; -moz-transition: all 0.4s ease-in; -o-transition: all 0.4s ease-in; transition: all 0.4s ease-in;
解决方案
1. 修复内容展开/收起动画
display: none 与 display: block 的切换无法触发过渡(无中间状态),改用高度变化实现动画:
修改 AccordionContent 样式:
export const AccordionContent = styled.div<AccordionContentProps>` padding: 0 18px; background-color: white; overflow: hidden; /* 用max-height实现自适应高度的过渡 */ max-height: ${props => props.isOpen ? '1000px' : '0'}; /* 同时过渡高度和内边距,避免内容突兀 */ transition: max-height 0.4s ease-in-out, padding-top 0.4s ease-in-out, padding-bottom 0.4s ease-in-out; padding-top: ${props => props.isOpen ? '18px' : '0'}; padding-bottom: ${props => props.isOpen ? '18px' : '0'}; `;
注:
1000px可根据实际内容高度调整,确保大于最大内容高度即可。
2. 修复图标切换动画
直接替换图标组件无法触发过渡,改用CSS旋转实现切换效果:
修改 index.tsx 代码
import { useState } from "react"; import { AccordionButton, AccordionContent, Wrapper } from "./styles"; import { AccordionProps } from "./interfaces"; import { BsChevronDown } from "react-icons/bs"; export default function Accordion({ title, text }: AccordionProps) { const [isOpen, setIsOpen] = useState(false); const handleClick = () => { setIsOpen(!isOpen); }; return ( <Wrapper> <AccordionButton onClick={handleClick}> {title} {/* 单个图标,通过类名控制旋转 */} <BsChevronDown className={isOpen ? 'icon-rotated' : ''} /> </AccordionButton> <AccordionContent isOpen={isOpen}> <p>{text}</p> </AccordionContent> </Wrapper> ); }
修改 AccordionButton 样式
export const AccordionButton = styled.button` background-color: #606582; color: #ffffff; cursor: pointer; padding: 18px; width: 100%; border: none; text-align: left; outline: none; font-size: 15px; transition: 0.6s; &:hover { background-color: #60658295; } > svg { float: right; /* 添加旋转过渡 */ transition: transform 0.4s ease-in-out; } /* 旋转样式 */ > .icon-rotated { transform: rotate(180deg); } `;
3. 额外优化
- 移除无用的
returnIcon函数,简化逻辑 - 确保
AccordionContentProps中isOpen定义为布尔类型
内容的提问来源于stack exchange,提问作者Gabriel
相关产品推荐
相关产品推荐

