※이번 포스트로 부터 나온 최종 아웃풋
https://frontend-bear.tistory.com/86
[HTML, CSS, JS] 바닐라 자바스크립트로 MBTI 테스트 만들기(1)에서 만들었던 객체를 이용해서,
이번엔 html 화면에서 직접 작동하게 만들어보자.
작업개요
- 이전 포스트에서 만들었던
PersonalTest
객체와 html을 연결 시켜보자. - 인트로, 테스트, 결과 페이지 구성
작업 가이드 및 사담
사실 이미 이전 포스트에서 거의다 끝내놓은 상태라,
금방 마무리 될 것 같다. 이번포스트에선 연결만 하고
다음 포스트에서 조금 더 디테일한 기능을 추가 및 리팩토링을해보자.
html과 css는 뭐 별다를게 없어서, 미리 만들어왔다.
화면 구성
혹시라도 css코드가 궁금하다면.. css 코드 확인
어쨌든! 이런 구성에 js에서 작성한 부분을 연결 시켜야 하니까 우선
html 코드를 보자.
<!DOCTYPE html>
<html lang="kr">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>개인 성향 검사</title>
<script src="./js/personalTest.js"></script>
<link rel="stylesheet" href="./css/style.css" />
</head>
<body>
<div class="personalTest_container">
<div class="intro_container content_container">
<h1>귀차니스트들을 위한 <span class="point_text">10초 MBTI 검사</span></h1>
<button class="start" type="button" data-action="start">시작하기</button>
</div>
<div class="test_container content_container">
<h2>
<span class="progress"></span>
<span class="question"></span>
</h2>
<div class="answer_container">
<button class="answer" type="button" data-answer="a"></button>
<button class="answer" type="button" data-answer="b"></button>
</div>
</div>
<div class="result_container content_container">
<h2 class="result_text"></h2>
<button class="restart" type="button" data-action="restart">다시하기</button>
</div>
</div>
<script>
const personalTest = new PersonalTest('.personalTest_container');
</script>
</body>
</html>
간단하게 구성해본 코드이다.
음. 이제 기존에 했던 js에서 render()
메서드를 위 html에 맞춰서 작성해주고,
여기저기 조금 손을 봐야한다.
render()
메서드부터 알아보자.
render() {
if(this.page === 0){
this.container.querySelector('.intro_container').classList.add('active');
this.container.querySelector('.test_container').classList.remove('active');
this.container.querySelector('.result_container').classList.remove('active');
}else if(this.page === 1){
this.container.querySelector('.test_container').classList.add('active');
this.container.querySelector('.intro_container').classList.remove('active');
this.container.querySelector('.result_container').classList.remove('active');
this.container.querySelector('.progress').textContent = `Q${this.progress + 1}. `
this.container.querySelector('.question').textContent = `${this.getCurrentQuestions().question}`;
this.container.querySelector('button[data-answer="a"]').textContent = `${this.getCurrentQuestions().answer.a}`;
this.container.querySelector('button[data-answer="b"]').textContent = `${this.getCurrentQuestions().answer.b}`;
}else if(this.page === 2){
this.container.querySelector('.result_container').classList.add('active');
this.container.querySelector('.intro_container').classList.remove('active');
this.container.querySelector('.test_container').classList.remove('active');
this.container.querySelector('.result_text').innerHTML = `당신의 성향은 <span class="point_text">${this.calcResult()}</span>입니다.`;
}
}
별로 이런 방식을 좋아하진 않지만 단순하게 짜봤다.render()
메서드가 동작할때마다 현 객체의 page 속성을 참조해서,
0번(intro)이면 intro_container
를 제외하고 active 제거,
1번(text)이면 test_container
를 제외하고 active 제거 이후progress
, question
, button[data-answer="a"]
, button[data-answer="b"]
에 각각
현재 객체의 progress + 1, 질문, 답변A, 답변B를 넣어주도록 작성했고,
2번(result)이면 result_container
를 제외한 active 제거 및result_text
에 결과 텍스트가 입력되도록 하였다.
이제 나머지 부분을 조금 수정해야하는데,
우선 init()
에 버튼이 작동하게끔 이벤트 리스너들을 달아줘야 한다.
init() {
this.questionArray = this.getQuestion(); // 질문을 배열로 저장
this.container.querySelector('button[data-answer="a"]')
.addEventListener('click', e => this.submitAnswer(e.target.innerText));
this.container.querySelector('button[data-answer="b"]')
.addEventListener('click', e => this.submitAnswer(e.target.innerText));
this.container.querySelector('button[data-action="start"]')
.addEventListener('click', this.start.bind(this));
this.container.querySelector('button[data-action="restart"]')
.addEventListener('click', this.restart.bind(this));
this.render();
}
bind()
를 사용해 버튼A, 버튼B, 그리고 시작하기와 다시하기에 이벤트리스너를 등록했고,this.render()
를 실행시켜 화면을 그려주었다.
다음은 start();
를 눌렀을때 시작되게 해야하니까 수정해보자.
start() {
if(this.progress !== 0) return; // 진행중이면 실행하지 않음
this.page = 1;
this.render();
}
start()
가 실행되면, page를 1로 바꿔주고 render()
를 실행시켜주었다.
기존에있던 return this.getCurrentQuestions(); 부분은 더이상 콘솔에서
확인할 필요가 없어졌기 때문에 제거했다.
restart()
는 기존에 없던 메서드지만 간단하다.
restart() {
this.page = 1;
this.progress = 0;
this.results = [];
this.render();
}
다시해야 하니까 page를 0으로 바꾸고~ progress를 0으로 바꾸고~
results를 비워주고 render()
을 이용해 화면을 다시 그려주면 된다.
이제 질문이 넘어갈때마다 화면을 새로그려주기만 하면되는데submitAnswer(answer)
메서드를 한번 수정해보자.
submitAnswer(answer) {
if(this.questionArray.length <= this.progress + 1){ // 질문이 끝났으면
this.page = 2;
this.render();
return;
}
this.results.push({
type: this.questionArray[this.progress].type,
answer: Object.keys(this.questionArray[this.progress].answer)
.find(selectedAnswer => {
return this.questionArray[this.progress].answer[selectedAnswer] === answer;
})
}); // 사용자가 선택한 답을 results에 추가 (type: 질문의 키, answer: 사용자가 선택한 답의 키)
this.progress++; // 질문 단계 증가
this.render();
return this.getCurrentQuestions();
}
기존에 this.questionArray.length <= this.progress
이부분이 조건이 잘못되있어서 수정했다.
해당 부분에서도 "당신의 성향은~ " 부분은 콘솔에서 확인하기 위해 찍어뒀던거라서,
역시나 제거하고, 겸사겸사 console.log도 제거했다.
그리고 나서, 질문이 끝났으면 page를 2로 바꿔주고 render,
그리고 그 외의 경우 progress가 +될때 (다음 질문으로 넘어갈때) render 한번 해주면 끝이다.
끝!
깨알팁!
간단하게 내 MBTI의 설명을 노출하고 싶다면 소소한 팁이있다.
어차피 calcResult()
메서드로 인해 MBTI는 ENFP, INFP 등으로 나온다.
그걸 이용할껀데 우선 createPersonalResult(totalResult)
에서 a와 b가 같을때를
★이 아니라 첫번째 영문으로 나오게 해주자.
그러면 온전히 MBTI 내에 속한 유형만 나오게 될껀데,constructor()
내부에 resultInfors
라는 객체를 하나 추가해주고,
this.resultInfors = {
ISTJ: {
title: '무조건 끝까지 해내는 당신!',
desc: '당신은 무조건 끝까지 해내는 사람입니다'
},
// ...
}
이렇게 작성해준다면, 최종 결과 페이지에서this.resultInfors[calcResult()].title
, this.resultInfors[calcResult()].desc
해주면 값을 불러올 수 있다.