자주 묻는 질문 답변 토글하기 🔫
과정
첫 번째 과제 내 첫 질문인 FAQ에서부터 꽉 막혔었다.
과제가 원하는 기능은 질문인 버튼 요소를 클릭하면 해당 요소의 형제 요소인 답변 요소가 보이게끔 하는 것이었다.
초기 버전은 이렇다.
1
2
3
4
5
6
7
const faqQuestionArray = document.querySelectorAll(".question");
for (const item of faqQuestionArray) {
item.addEventListener("click", function (event) {
// TO DO LIST
});
}
과제가 원하는 기능의 예시
빨강 박스를 누르면,
\[\huge {↓}\]답변 박스가 나타나게 된다.
먼저 생각했던 것은 초기코드 내에 먼저 .question 속성을 가지는 모든 값을 반환하여 한 배열로 만든 faqQuestionArray 변수에 대해 이해하는 것이었다. 결국 이 변수가 배열이면 이 배열의 특정 요소의 index 값을 가지고 오게 되면 형제 요소인 답변 요소에 그 index 값을 넣어 내가 누르고자 하는 질문 버튼 태그의 형제 요소인 질문 요소에 접근할 수 있지 않을까였다.
그래서 우선 faqQuestionArray과 같은 개념으로 answer에 대한 배열 또한 querySelectorAll을 사용하여 faqAnswerArray라는 변수로 가지고 왔다.
1
2
3
4
5
6
7
8
const faqQuestionArray = document.querySelectorAll(".question");
const faqAnswerArray = document.querySelectorAll(".answer");
for (const item of faqQuestionArray) {
item.addEventListener("click", function (event) {
// TO DO LIST
});
}
다음으로 faqQuestionArray 배열을 for…of문에 의하여 1번 질문 버튼을 누르면 1번 질문 버튼의 배열 내 index 값인 ‘0’을 가져오는 것이었다. 아래가 해당 logic.
1
Array.from(faqQuestionArray).indexOf(item)
해당 질문 버튼의 index 값인 0을 faqAnswerArray 배열에 넣으면, 같은 순서로 faqAnswerArray 내 위치한 요소를 가지고 올 수 있었다.
1
faqAnswerArray[Array.from(faqQuestionArray).indexOf(item)]
그 다음 해당 요소의 style = display : none 값에 접근하여 block이라는 값으로 바꿔준다면 질문 버튼을 눌렀을 때 답변이 보일 것이라 추측했다.
1
2
3
4
if (faqAnswerArray[Array.from(faqQuestionArray).indexOf(item)].style.display = "none")
{
faqAnswerArray[Array.from(faqQuestionArray).indexOf(item)].style.display = "block";
}
결과는 의도했던 바와 같이 성공하였고,
1
2
3
4
5
6
7
8
if (faqAnswerArray[Array.from(faqQuestionArray).indexOf(item)].style.display = "none")
{
faqAnswerArray[Array.from(faqQuestionArray).indexOf(item)].style.display = "block";
}
else if (faqAnswerArray[Array.from(faqQuestionArray).indexOf(item)].style.display = "block")
{
faqAnswerArray[Array.from(faqQuestionArray).indexOf(item)].style.display = "none";
}
else문을 추가해 그 반대로도 구현하면 완성일거라 생각했지만, 그 반대로 닫는 기능 구현은 실패하였다.
우선 디버깅을 위하여 각 if와 else if 안에 console.log를 호출하였는데,
1
2
3
4
5
6
7
8
9
10
if (faqAnswerArray[Array.from(faqQuestionArray).indexOf(item)].style.display = "none")
{
console.log('open');
faqAnswerArray[Array.from(faqQuestionArray).indexOf(item)].style.display = "block";
}
else if (faqAnswerArray[Array.from(faqQuestionArray).indexOf(item)].style.display = "block")
{
console.log('close');
faqAnswerArray[Array.from(faqQuestionArray).indexOf(item)].style.display = "none";
}
위 사진과 같이 버튼을 누를 때 마다, 원했던 else if문은 실행이 안되고 if문 내에 있는 console.log(’open’)만 반복호출되는 것을 확인했다.
안되는 이유에 대하여 멘토 분께 질문을 드렸다. 우선 내가 썼던 이 logic에서
1
faqAnswerArray[Array.from(faqQuestionArray).indexOf(item)].style.display = "none"
결국 “none”이라는 값을 해당 객체에게 할당시키는 것이 오류가 나지 않을까라는 말을 듣고,
내 원래 의도로 실행되려면 ‘===’을 써야 되는 것을 알았다.
아래처럼 모든 ‘=’을 ‘===’로 바꿔 실행해봤다.
1
faqAnswerArray[Array.from(faqQuestionArray).indexOf(item)].style.display === "none"
안타깝게도 답변을 여는 것 또한 실행되지 않았다. 내가 실행하려고 한 logic 자체가 문제이지 않았을까 생각이 들었다. 그래서 다른 방법으로 답변 요소를 여는 방법을 찾아야 했다.
그래서 먼저 보기 너무 복잡한 위의 logic으로 인해 쉽게 발견될만한 오류를 못 보고있을 수도 있다고 생각하여 한 변수에 할당시켜 보기로 했다.
siblingTag라는 변수에 question과 answer 각 배열 내에 특정 question과 같은 index 값을 가지는 answer를 할당하기로 했다. 즉 question 태그의 바로 옆에 있는 형제요소인 answer 태그에 접근하기로 했다.
1
let siblingTag = faqAnswerArray[Array.from(faqQuestionArray).indexOf(item)];
그 다음, if문을 써서 siblingTag(특정 question버튼태그 옆 형제요소 answer태그)의 style에 접근해서 display가 none이면 block으로 block이면 none으로 바꿔줬다.
1
2
3
4
5
6
7
8
9
10
11
let siblingTag = faqAnswerArray[Array.from(faqQuestionArray).indexOf(item)];
if (siblingTag.style.display === "none")
{
//console.log('open');
siblingTag.setAttribute("style", "display: block");
}
else{
//console.log('close');
siblingTag.setAttribute("style", "display: none");
}
결과
그 이후 실행시켜보니 아까와 같은 오류 없이 정상적으로 열기/닫기가 작동하는 것을 확인했다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const faqQuestionArray = document.querySelectorAll(".question");
const faqAnswerArray = document.querySelectorAll(".answer");
for (const item of faqQuestionArray) {
item.addEventListener("click", function (event) {
let siblingTag = faqAnswerArray[Array.from(faqQuestionArray).indexOf(item)];
if (siblingTag.style.display === "none")
{
siblingTag.setAttribute("style", "display: block");
}
else
{
siblingTag.setAttribute("style", "display: none");
}
});
}
위 처럼 display: none이라 숨겨져 있던 답변 태그에 display: block으로 바뀌는 것을 볼 수 있다.