개요
저번에 만들었던 MBTI 테스트는 각 성향별 질문을 하고,
성향에 맞는 결과페이지를 보여주는 방식이였는데, 심리테스트나 OOO테스트 이런것들 중에는
점수를 누적시켜서 점수에 따른 결과를 보여주는 방식과 주어진 질문들을 따라가서
(질문의 답변에 따라 다음 질문이 분기됨) 최종적으로 결과페이지가 나오는 방식이 있다.
물론 html 페이지를 여러장 만들어서 버튼마다 연결연결 시키는 방법도 있겠지만
전체적으로 자바스크립트로 라이브러리 형식으로 만들어보면 재밌지 않을까?
라는 마음에서 시작해서 등록을 쉽게 만들어서 심리테스트들이 모여있는 페이지를 만들어보는것도
재밌을거 같다고 생각이 들어서 진행하게 되었다.
(이미 더 쉽게 심리 테스트를 만들 수 있는 사이트들이 있지만.)
구상
우선 점수 누계형 / 성향 분석형 / 길목형(?) 이렇게 3가지의 분류로 나눠볼 예정이고,
각 분류에 따라 넣어야 하는 데이터의 형태도 다른식으로 적용해야 할 것 같다.
타이틀 페이지의 구성은 "테스트 이미지"/"테스트 제목" / "테스트 설명" / "총 문항 및 소요 시간"/"시작하기 버튼"
이렇게 5가지의 컴포넌트로 구성될 예정이고 이중 테스트 이미지와 테스트 설명은 없어도 오류가 안나게끔 작업한다.
시작하기 버튼의 텍스트는 테스트 데이터에 별도의 버튼 텍스트가 없으면 "시작하기"로 초기값이 설정되어 있고,
테스트 데이터에서 시작하기 버튼의 텍스트가 전달될 경우 버튼의 텍스트를 변경해준다.
우선 이번 포스트에서는 점수형부터 작업을 진행해볼 예정이다.
일단, 폴더 구조는 아래와 같이 정리 하였다.
css 에는 reset.css 와 전체적인 css 코드가 담기는 style.css
js에는 페이지의 이런저런 스크립트가 담길 common.js (주로 클래스가 담길 예정)
src 폴더 내에는 테스트의 정보가 담긴 필요한 json 파일들을 넣어둘 예정이고
index.html은 실제로 보여질 페이지이다.
HTML 구성
위에서 구상했던것 처럼, index.html을 구상해보자.
<div class="view_container">
<div class="content_wrap">
<div class="title">테스트의 제목</div>
<div class="description">테스트의 설명</div>
<ul class="information">
<li>
<span>총 문항 :</span>
<span id="question_length">테스트 총 문항 수</span>
</li>
<li>
<span>소요시간 :</span>
<span id="time">테스트의 소요 시간</span>
</li>
</ul>
</div>
<div class="button_wrap">
<button type="button" class="start_btn">시작하기</button>
</div>
</div>
적당히 저런 느낌의 페이지가 나오면 좋을것 같다.
갑자기 든 생각인데, 폰트를 이것저것 설치해두고, 폰트 타입도 설정이 가능 하면 좋을것 같다.
일단 이건 메모장에 메모해두는걸로..
우선 위에 이미지 파일을 보면,
타이틀은 "나와 닮은 동물 찾기" 설명에는 "🐱🦁🐯🦒🦊🦝🐮🐷🐗🐭🐰🐻" 이런 동물 이모지들
총문항은 실제 총 문항이 나오게 하고, 소요 시간은 문항당 10초 ~ 문항당 20초로 하면 적당할 것 같다.
분 이하는 삭제하면 좋을듯. 아 그리고 최소 소요시간이 1분 미만일 경우 "1분 미만" 이라고 표시되게 하자.
(현재 10문항이니 100초(1분 40초) ~ 200초(3분 20초) : 1 ~ 3분
그리고 버튼 텍스트는 "닮은 동물 찾아보기" 로 설정되어있다.
테스트의 형태는 당연히 이번 포스트가 점수형인 만큼 "point"로 지정해두면 될 것 같다.
JSON 데이터 형식 구성
위 데이터를 우선 json 으로 표현해보면
{
"title": "나와 닮은 동물 찾기",
"description": "🐱🦁🐯🦒🦊🦝🐮🐷🐗🐭🐰🐻",
"type": "point",
"startButtonText": "닮은 동물 찾아보기",
}
이정도? 문항과 결과는 따로 배열의 형태로 data와 result로 구분해주자.
{
"title": "나와 닮은 동물 찾기",
"description": "🐱🦁🐯🦒🦊🦝🐮🐷🐗🐭🐰🐻",
"type": "point",
"startButtonText": "닮은 동물 찾아보기",
"data": [],
"result": []
}
data에는 객체의 형태로 각 질문과 그에 맞는 대답이 들어갈꺼고, 대답에 따라서 부여되는 점수가 다를 수 있고,
추후 문제별로 이미지를 노출해주는 경우도 있을것 같아서 객체로 지정했다.
적당한 이름으로 저장해 src 폴더에 넣어주자.
그리고 이제 common.js로 이동해서 class를 하나 생성해줄건데, 테스트 전체의 정보를 담는 객체로 구성 될 예정이다.
JS 초기화 설정
class TestPage {
constructor(data) {
this.title = data.title;
this.desc = data.description;
this.testLength = data.data.length;
this.startButton = data.startButtonText;
this.current = 0; // 현재 진행중인 문제 번호
this.question = data.data;
this.result = data.result;
if(data.type === 'point') this.point = 0;
this.init();
}
init(){
...
}
}
기본적인 constructor의 구성만 해보면, 우선 data는 위에서 생성한 json 자체를 입력할 예정이고,
해당 json에서 title, description, testLength(data의 원소 갯수), startButton의 텍스트, 질문들을 담아둘 question,
결과들을 담아둘 result를 생성해주었다.
json에서 받은 데이터 외에 객체가 스스로 가져야할 속성으로,
테스트의 type이 "point"일때 점수를 누적시키기 위해 point를 생성했고,
현재 진행중인 문제의 번호를 파악하기 위해 current라는 변수를 하나 더 생성해준 뒤,
최초 초기화를 위해 init() 매서드를 실행해주었다.
이제 초기 화면을 구성하는 init 매서드 내용을 채워보자.
init() {
document.querySelector('.title').innerHTML = this.title;
document.querySelector('.description').innerHTML = this.desc;
document.querySelector('#question_length').innerHTML = `${this.testLength}문항`;
if(Math.trunc(this.testLength * 10 / 60) > 0){
document.querySelector('#time').innerHTML = Math.trunc(this.testLength * 10 / 60) + ' ~ ' + Math.trunc(this.testLength * 20 / 60) + '분';
}else{
document.querySelector('#time').innerHTML = `1분 이내`;
}
document.querySelector('.start_btn').innerHTML = this.startButton || '시작하기';
document.querySelector('.start_btn').addEventListener('click', () => {
this.start();
});
}
클래스를 생성될 때 인자로 DOM을 받아서 해당 DOM 내부에 들어가도 괜찮을것 같은데,
지금은 한페이지에 하나의 테스트만 존재할 예정이니, 따로 그렇게는 안하고 바로 document에서
아까 지정해둔 html의 class들을 활용해서 내용들을 바꿔준다.
.title의 내용을 constructor에서 지정한 this.title로, .description의 내용을 this.desc로 바꾸는 식으로 우선
타이틀과 설명을 바꿔주고, 위에서 미리 선언해준 testLength로 문항의 갯수,
그리고 문항의 갯수에 10을 곱한 뒤, 60으로 나눠준것과 ( 문항당 10초를 곱해준 뒤 분으로 변환 )
20을 곱한뒤 60으로 나눠준것으로 소요시간을 넣어준다. ( 둘다 소숫점 이하는 버려준다 )
이때 10을 곱한 뒤, 60으로 나눠준 값이 0보다 작을 경우 "1분 이내" 라는 텍스트로 수정해준다.
시작하기 버튼도 this.startButton이 있다면 해당 내용으로, 없다면 "시작하기"로 바꿔준다.
생각해보니 여기서 안하고 constructor부분에서 하는게 좀 더 나을거 같긴한데,
일단 큰 문제는 안될것 같으니 진행하자.
여튼 이후에 start 버튼이 클릭될 경우 테스트가 시작되게끔 아직 선언해두진 않았지만 this.start() 매서드를
연결시켜주자. 일단 오류방지를 위해 start() 매서드도 하단에 추가 해준뒤 html로 돌아가자.
중간 확인용 전체 코드
class TestPage {
constructor(data) {
this.title = data.title;
this.desc = data.description;
this.testLength = data.data.length;
this.startButton = data.startButtonText;
this.current = 0;
this.question = data.data;
this.result = data.result;
if(data.type === 'point')this.point = 0;
this.init();
}
init() {
document.querySelector('.title').innerHTML = this.title;
document.querySelector('.description').innerHTML = this.desc;
document.querySelector('#question_length').innerHTML = `${this.testLength}문항`;
if(Math.trunc(this.testLength * 10 / 60) > 0){
document.querySelector('#time').innerHTML = Math.trunc(this.testLength * 10 / 60) + ' ~ ' + Math.trunc(this.testLength * 20 / 60) + '분';
}else{
document.querySelector('#time').innerHTML = `1분 이내`;
}
document.querySelector('.start_btn').innerHTML = this.startButton || '시작하기';
document.querySelector('.start_btn').addEventListener('click', () => {
this.start();
});
}
start() {}
}
HTML - JSON 요청 및 시작 페이지 적용
이제 html의 head 태그 내에 common.js를 불러와준 뒤,
body 최하단에서 JSON을 불러온 뒤, 방금 만들었던 TestPage 클래스를 생성해서
제대로 html의 제목과 내용, 버튼명이 변경되는지 테스트를 해보자.
<!DOCTYPE html>
<html lang="kr">
<head>
...
<script src="./js/common.js"></script>
</head>
<body>
...
<script>
fetch('./src/likeAnimal.json')
.then((response) => response.json())
.then((data) => new TestPage(data))
</script>
</body>
</html>
fetch 매서드를 이용해 상대경로로 src폴더의 likeAnimal.json을 호출하고,
그 결과를 json 매서드를 이용해서 변환 후 TestPage 객체를 생성해주었다.
그리고 나서, 제대로 작동하는지 확인해보면 정상적으로 반영되는걸 확인 할 수 있다.
JSON 파일의 data에 [0,0,0,0,0,0,0] 이런식으로 임시로 내용을 추가해보면
총문항과 소요시간도 변경되는걸 확인 할 수 있다.
다음 포스트에서는 this.start()와 this.next() 매서드를 만들어서 실제로 테스트가 동작하게끔 해보자.