前提・実現したいこと
現在、サイト制作をしていくうえでアコーディオンのクリック部分での質問がありましたので、スレッドを立てました。
実現したいところといたしましては、開いているアコーディオンをクリックした時に閉じたい
という部分についてお聞きできればと思います。
#実際のコード
Parent
1import classes from './index.module.scss' 2import { Accordion } from './accordion' 3import { useCallback, useState } from 'react'; 4 5const accordionItems = [ 6 { 7 title: '', 8 text: [ 9 '', 10 ], 11 }, 12 { 13 title: '', 14 text: [ 15 '', 16 ], 17 }, 18 { 19 title: '', 20 text: [ 21 '', 22 '', 23 '', 24 ], 25 }, 26 { 27 title: '', 28 text: [ 29 '', 30 ], 31 }, 32 { 33 title: '', 34 text: [ 35 '', 36 ], 37 }, 38 { 39 title: '', 40 text: [ 41 '', 42 ], 43 }, 44 { 45 title: '', 46 text: [ 47 '', 48 ], 49 }, 50 { 51 title: '', 52 text: [ 53 '', 54 ], 55 }, 56] 57 58const defaultOpenIndex = 0; 59 60export const TopQuestion = () => { 61 62 const [openIndex, setIndex] = useState(defaultOpenIndex); 63 64 const changeIndex = useCallback((index: number) => { 65 setIndex(index); 66 }, []); 67 68 return ( 69 <div className={classes.wrapper}> 70 <div className={classes.contents}> 71 <div className={classes.about}> 72 <div className={classes.title}> 73 <h2>質問と回答</h2> 74 <p>より多くの質問と回答はFAQからご覧ください</p> 75 </div> 76 {[...accordionItems].map((item, i) => { 77 return ( 78 <div className={classes.accordionWrapper} key={i}> 79 <Accordion 80 title={item.title} 81 flag={openIndex === i} 82 changeIndex={changeIndex} 83 index={i} 84 > 85 {item.text.map((text, index) => { 86 return ( 87 <p key={index} className={classes.accordionText}> 88 {text} 89 </p> 90 ); 91 })} 92 </Accordion> 93 </div> 94 ); 95 })} 96 </div> 97 </div> 98 </div> 99 ); 100}
child
1import classes from "./index.module.scss"; 2import React from "react"; 3 4export type Props = { 5 title: string; 6 flag: boolean; 7 index: number; 8 changeIndex:(index: number) => void; 9 children: React.ReactNode; 10}; 11 12export const Accordion: React.VFC< 13Props 14> = React.memo(({title, index, changeIndex, flag, children}) => { 15 return ( 16 <div className={classes.accordionWrapper}> 17 <div 18 className={`${classes.accordionTitle} ${ 19 flag ? classes.open : "" 20 }`} 21 onClick={(e) => { 22 e.preventDefault(); 23 changeIndex(index); 24 }} 25 > 26 <p>{title}</p> 27 </div> 28 <div 29 className={`${classes.accordionItem} ${ 30 flag ? "" : classes.collapsed 31 }`} 32 > 33 <div className={classes.accordionContent}> 34 <div>{children}</div> 35 </div> 36 </div> 37 </div> 38 ); 39})
scss
1.wrapper { 2 width: 600px; 3 margin: 0 auto; 4} 5 6.accordionWrapper { 7 & + * { 8 margin-top: 0.5em; 9 } 10} 11 12.accordionItem { 13 overflow: hidden; 14 transition: max-height 0.3s cubic-bezier(1, 0, 1, 0); 15 height: auto; 16 max-height: 9999px; 17} 18 19.accordionItem.collapsed { 20 max-height: 0; 21 transition: max-height 0.35s cubic-bezier(0, 1, 0, 1); 22} 23 24.accordionTitle { 25 position: relative; 26 cursor: pointer; 27 color: #333; 28 padding: 0.5em 1.5em; 29 margin-bottom: 15px; 30 border-radius: 2px; 31 display: flex; 32 justify-content: space-between; 33 align-items: center; 34 transition: all 0.3s; 35 background-color: #fff; 36 box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.2); 37 38 p { 39 font-size: 12px; 40 } 41 42 &::before, &::after { 43 content: ""; 44 display: block; 45 position: absolute; 46 top: 50%; 47 right: 50px; 48 width: 10px; 49 height: 2px; 50 border-radius: 5px; 51 background: #333; 52 opacity: 1; 53 transition: .4s; 54 } 55 56 &::before { 57 transform: rotate(90deg); 58 } 59 60 &:hover, 61 &.open { 62 color: #00bcd4; 63 &::before, &::after { 64 background: #00bcd4; 65 } 66 } 67 68 &.open { 69 &::before { 70 content: ""; 71 opacity: 0; 72 transition: .4s; 73 } 74 } 75} 76 77.accordionContent { 78 padding: 1em 1.5em; 79} 80 81.accordionContent > p { 82 font-size: 14px; 83} 84
#知りたいこと
現状は親要素でnuber型のuseStateを持ち、
openIndexがindex番号と同じならflagにtrueが入り、アコーディオンが開く設計にしています。
ただ、この設計だと初期画面で一つ目のアコーディオンが開き、他のアコーディオンを開くたびにもともと開いていたアコーディオンが閉まっていきますが、現状開いているアコーディオンをクリックしても閉まりません。
ここで何を実行すればアコーディオンが閉まるようになるのかのアドバイスをいただきたいです。
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。