[PJT] vanillaJS로 quiz webApp 만들기

돗개·2021년 1월 6일
0

vanillaJS 프로젝트

목록 보기
2/2

Quiz webApp

오늘은 비교적 쉬운? 미니 프로젝트 quiz app을 만들었다.
문제를 풀고, 자동 채점되어 정오표까지 알려주는 웹앱이다.

- setting


- quizData

질문과 선지(a, b, c, d), 그리고 정답이 포함된 객체로 이루어진 quizData 배열을 만든다.
질문은 구글에서 짧은 문제 위주로 찾아서 5문제를 작성했다. (은근 헷갈리는 문제들로 ㅎㅎ)


- 선택지

1) radio type

선지들은 input 태그에서 타입을 "radio"로 주었다.
선지들이 다중으로 선택되는 것을 막기 위해, 각 선지별로 동일한 name을 지정해 주어야 한다는 사실을 배웠다.


2) label tag

각 선지의 텍스트는 <label>태그로 감싸주었는데, 그 이유는 라디오 버튼이나 체크박스를 클릭할 때, 버튼 옆 텍스트를 클릭해도 해당 버튼이 선택되도록 해주기 때문이다!

<input type="radio" id="a" class="answer" name="myRadio">
<label id="a_text" for="a">answer</label>

- next button

next button을 클릭할 때마다 togoNext라는 함수(다음 페이지를 로드하는)를 실행시킨다. 다음 페이지는 currentNum이라는 변수를 두어 인덱스 번호가 하나씩 올라갈 수 있도록 했다. (quizData의 길이 내에서)

1) .checked

답을 체크하지 않았을 경우, 다음으로 넘어가면 안되기 때문에, 예외처리를 해주어야 한다. selected라는 함수를 만들고, 체크되었다면 answer 요소의 id를, 체크가 안되었다면 undefined를 리턴하도록 했다. (답을 체크한 김에 정답과 비교하는 작업도 여기서 진행했다.)

function selected() {
  let answer = undefined;
  answerEls.forEach((answerEl) => {
    if (answerEl.checked) {
      // 채점 로직
      answer = answerEl.id;
    };
  });
  return answer;
}

반환 값을 토대로 undefined시, alert 창이 뜨도록 하고,
값이 존재한다면 currentNum++을 해주고, 다음 퀴즈객체가 로드되도록 해준다.


- check score

위의 selected 함수 내에 채점하는 로직을 작성했다.
answer 요소의 id가 quizData의 현재 인덱스의 정답값과 같다면 score++를 해준다.

마지막 퀴즈를 풀고 다음 버튼을 누르면, 점수 결과를 보여주는 함수를 작성했다.
전체 퀴즈 폼을 DOM 선택하여 innerHTML로 결과 페이지를 삽입했다.
저번에 타이머 만들 때는 요소 하나씩만 사라지고 보여져야 해서 귀찮았는데, 전체가 바뀌어 한 방에 해결하니 좋았다..


- reload

버튼 클릭 시, reload 함수를 실행시켜 새로고침 되도록 했다.
<button>다시 풀기</button>



뭔가 심심해서, 간단한 세 가지 기능을 추가해보기로 했다.
1) 마지막 문제에서 '다음 문제'버튼이 '제출하기'로 변경
2) 몇 번 문제를 맞췄고, 틀렸는지 보여주는 정오표
3) 퀴즈 풀이 진행 정도를 알려주는 progress bar

코드 작성은 어렵지 않았지만, 어디 함수 어디 순서에 들어가야 할지가 좀 헷갈렸다;;

- submit button

인덱스가 마지막일 때 버튼 텍스트가 바뀌어야 하는데, 바로 이전 문제에서 다음문제 버튼을 눌렀을 때, 마지막 퀴즈가 로드되므로 togoNext 함수에서 퀴즈 로드하는 함수를 불러온 뒤에, 인덱스 조건을 넣었다.


- 정오표

정오표를 위해 체크한 답을 저장하는 배열을 만들고, 맞으면 'O'를 push, 틀리면 'X'를 push 했다. 이건 답을 채점하는 부분에 넣어줬다.
다음으로 table 태그로 깔끔히 정리해 주었다.


- progress

문제 풀이 진행 정도를 알려주는 bar를 넣고 싶었는데, 구글링 해보니 progress 태그가 있었다. 어려울 줄 알았는데 태그 하나만 삽입해서 쉽게 구현했다.
진행 정도는 value 값을 20씩 늘려주면서 높여갔다. 기본 스타일링이 깔끔해서 따로 스타일링은 하지 않았다.


- Issues

1) deselect answer

답을 체크하고 넘어가면 다음 페이지에서도 그 부분이 체크되어 있었다. deselectAnswer 함수를 만들고, .checked = false로 바꿔주었다. 다음 퀴즈가 로드되면, 체크를 없애주는 이 함수를 실행시켜 디버깅했다.

function deselectAnswer() {
  answerEls.forEach((answerEl) => {
    answerEl.checked = false;
  });
}

2) 예외처리

- 마지막 장에서 답을 선택하지 않았을 때,

제출 버튼을 누르면, alert 창이 뜬 뒤 (화면이 킵되지 않고) 정오표 화면으로 넘어가버렸다.
버튼 클릭 이벤트가 발생하는 부분을 잘못 작성했다고 판단했고, 문제를 찾았다.
'다음 문제' 버튼을 '제출하기'로 바꾸고, 새로 addEventListener를 작성한 것이 문제였다. 이름만 바뀐 것이고 어쨌든 버튼은 하나이므로, 처음 click 이벤트가 발생한 부분 내부에 조건처리(if 마지막 인덱스) 하여 올바르게 작동하도록 했다.


느낀점..

이번 웹앱은 크게 어려운 점 없이 구현할 수 있었다. 구글링하여 새로 알게된 태그와 속성들이 많았고, 배열과 인덱스 자료구조를 잘 활용했다.

  • 이벤트 발생 순서 이해하기
    : 버튼을 클릭할 때, 많은 로직들이 어떻게 순서대로 진행되어야 하는지 차분하게 생각해봐야겠다. 코테를 풀 때도 그렇지만, 예외처리 부분이 항상 먼저 나와 예외인 상황을 걸러주어야 한다.
  • 속성 구글링하기
    : 원하는 기능을 새로 구현하고 싶을 때, 속성을 잘 찾아보면 빠르고 쉽게 구현할 수 있다는 사실을 알았다.
profile
울보 개발자(멍.. 하고 울어요)

0개의 댓글