“ 당신이 6개월 이상 한 번도 보지 않은 코드는 다른 사람이 다시 만드는 게 훨씬 더 나을 수 있다. ”
자바스크립트 퀴즈(Quiz) 사이트 만들기
이번에 만들어 본 퀴즈 사이트는 객관식(슬라이드) 확인하기(여러문제) 유형입니다.
한번 풀어보세요! 마지막 문제까지 풀면 하단에 점수와 맞힌 개수가 나옵니다!
퀴즈 사이트 코드
<!DOCTYPE html>
<html lang="ko">
<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>퀴즈 이펙트06</title>
<link rel="stylesheet" href="css/reset.css">
<link rel="stylesheet" href="css/quiz.css">
<style>
</style>
</head>
<body>
<header id="header">
<h1><a href="../javascript14.html">Quiz</a> <em>객관식(슬라이드) 확인하기(여러문제) 유형</em></h1>
<ul>
<li><a href="quizEffect01.html">1</a></li>
<li><a href="quizEffect02.html">2</a></li>
<li><a href="quizEffect03.html">3</a></li>
<li><a href="quizEffect04.html">4</a></li>
<li><a href="quizEffect05.html">5</a></li>
<li><a href="webd05-1.html">5-1</a></li>
<li class="active"><a href="quizEffect06.html">6</a></li>
</ul>
</header>
<!-- //header -->
<main id="main">
<div class="quiz__wrap">
<div class="quiz">
<div class="quiz__header">
<h2 class="quiz__title"></h2>
</div>
<div class="quiz__main ">
<div class="quiz__question"></div>
<h4></h4>
<div class="quiz__view">
<div class="dog__wrap">
<div class="true">😇정답입니다!</div>
<div class="false">😈틀렸습니다!</div>
<div class="card-container">
<div class="dog">
<div class="head">
<div class="ears"></div>
<div class="face"></div>
<div class="eyes">
<div class="teardrop"></div>
</div>
<div class="nose"></div>
<div class="mouth">
<div class="tongue"></div>
</div>
<div class="chin"></div>
</div>
<div class="body">
<div class="tail"></div>
<div class="legs"></div>
</div>
</div>
</div>
</div>
</div>
<div class="quiz__choice"></div>
<div class="quiz__answer">
<button class="next">다음 문제</button>
</div>
<div class="quiz__desc"></div>
<div class="quiz__info"><b>??점</b></div>
<div class="quiz__check">💛 총 <span>❔</span>개 💛</div>
</div>
</div>
</div>
</main>
<!-- //main -->
이번에 만든 사이트는 전에 만들어 본 퀴즈 사이트들과 다르게 남은 문제의 수를 보여주게 만들었습니다.
그리고 점수와 다 풀고 맞힌 개수도 보여주게 만들었습니다.
script 코드
<script>
//문제 정보
const quizInfo = [
{
infoType : "정보처리 기능사",
infoTime : "2006년 5회",
infoNumber : "20060501",
infoQuestion : "아래의 논리 대수식을 갖는 게이트(gate)는?",
infoChoice : ["NOR", "AND", "NAND", "XOR"],
infoAnswer: "NAND",
infoDesc : "<br>AND 전체에 NOT가 되어 있습니다.<br>NOT AND 이므로 NAND가 됩니다."
},{
infoType : "정보처리 기능사",
infoTime : "2006년 5회",
infoNumber : "20060502",
infoQuestion : "2진수 1011을 그레이코드(gray code)로 변환하면?",
infoChoice : ["1010", "0100", "0111", "1110"],
infoAnswer: "1110",
infoDesc : "<br>2진수를 그레이코드로 변환하는 방법은 첫번째 숫자는 그냥 내리고 나머지는 옆에것을 더해서 내려주면 됩니다."
},{
infoType : "정보처리 기능사",
infoTime : "2006년 5회",
infoNumber : "20060503",
infoQuestion : "이항(binary) 연산에 해당하는 것은?",
infoChoice : ["COMPLEMENT", "AND", "ROTATE", "SHIFT"],
infoAnswer: "AND",
infoDesc : "<br>단항연산 : ROTATE, SHIFT, MOVE, NOT(COMPLEMENT) 입니다. "
},{
infoType : "정보처리 기능사",
infoTime : "2006년 5회",
infoNumber : "20060504",
infoQuestion : "다음 그림의 연산결과는?",
infoChoice : ["1010", "1110", "1101", "1001"],
infoAnswer: "1010",
infoDesc : "<br>1110 AND 1010의 결과를 묻는 문제 입니다."
},{
infoType : "정보처리 기능사",
infoTime : "2006년 5회",
infoNumber : "20060505",
infoQuestion : "인스트럭션 레지스터(Instruction register), 부호기, 번지해독기, 제어계수기 등과 관계있는 장치는?",
infoChoice : ["제어장치", "연산장치", "입력장치", "기억장치"],
infoAnswer: "제어장치",
infoDesc : "<br>제어 계수기에서 힌트를 얻을수 있습니다.<br>제어장치의 일종입니다."
},{
infoType : "정보처리 기능사",
infoTime : "2006년 5회",
infoNumber : "20060506",
infoQuestion : "언어번역 프로그램(Language translator)에 해당하지 않는 것은?",
infoChoice : ["컴파일러", "어셈블러", "인터프리터", "로더"],
infoAnswer: "로더",
infoDesc : "<br>로더는 번역된 프로그램을 실행하는데 관련이 있습니다.<br>간단히 실행관련이라고 할수 있습니다."
}
];
//선택자
const quizWrap = document.querySelector(".quiz__wrap");
const quizMainH4 = document.querySelector(".quiz__main h4");
const quizTitle = quizWrap.querySelector(".quiz__title");
const quizQuestion = quizWrap.querySelector(".quiz__question");
const quizChoice = quizWrap.querySelector(".quiz__choice");
const dogWrap = quizWrap.querySelector(".dog__wrap");
const quizAnswer = quizWrap.querySelector(".quiz__answer");
const quizNext = quizWrap.querySelector(".quiz__answer .next");
const quizDesc = quizWrap.querySelector(".quiz__desc");
const quizCheck = quizWrap.querySelector(".quiz__check span");
let quizCount = 0;
let quizScore = 0;
const updateQuiz = (index) => {
let typeTag = `
<span>${quizInfo[index].infoType}</span>
<em>${quizInfo[index].infoTime}</em>
`;
let questionTag = `
<em>${index+1}</em>.
<span>${quizInfo[index].infoQuestion}</span>
`;
let choiceTag = `
<label for="choice1">
<input type="radio" id="choice1" name="choice" value="1">
<span>${quizInfo[index].infoChoice[0]}</span>
</label>
<label for="choice2">
<input type="radio" id="choice2" name="choice" value="2">
<span>${quizInfo[index].infoChoice[1]}</span>
</label>
<label for="choice3">
<input type="radio" id="choice3" name="choice" value="3">
<span>${quizInfo[index].infoChoice[2]}</span>
</label>
<label for="choice4">
<input type="radio" id="choice4" name="choice" value="4">
<span>${quizInfo[index].infoChoice[3]}</span>
</label>
`;
let descTag = `
정답은 ${quizInfo[index].infoAnswer}입니다.<br>
${quizInfo[index].infoDesc}
`;
let h4Tag = `
총 ${quizInfo.length - index}문제 남았습니다.
`;
quizTitle.innerHTML = typeTag;
quizQuestion.innerHTML = questionTag;
quizChoice.innerHTML = choiceTag;
quizDesc.innerHTML = descTag;
quizMainH4.innerHTML = h4Tag;
//보기 선택자
const quizChoiceSpan = quizWrap.querySelectorAll(".quiz__choice span");
const quizChoiceInput = quizWrap.querySelectorAll(".quiz__choice input");
//for문
for(let i=0; i<quizChoiceSpan.length; i++){
quizChoiceSpan[i].setAttribute("onclick", "choiceSelected(this)");
}
//다음 버튼 숨기기, 해설 숨기기
quizAnswer.style.display = "none";
quizDesc.style.display = "none";
};
updateQuiz(quizCount);
function choiceSelected(answer){
let userAnswer = answer.textContent; //사용자 정답
let currentAnswer = quizInfo[quizCount].infoAnswer; //문제 정답
if(userAnswer == currentAnswer){
dogWrap.classList.add("like");
dogWrap.classList.remove("dislike");
quizScore++;
} else {
dogWrap.classList.remove("like");
dogWrap.classList.add("dislike");
}
//다음 버튼, 해설 나타나기
quizAnswer.style.display = "block";
quizDesc.style.display = "block";
if(quizInfo.length - quizCount == 1){
document.querySelector(".quiz__info").innerHTML = Math.ceil((quizScore / quizInfo.length) * 100) + "점";
quizCheck.innerHTML = quizScore;
}
};
//정답 확인
quizNext.addEventListener("click", () => {
quizCount++;
updateQuiz(quizCount);
dogWrap.classList.remove("like", "dislike");
});
</script>
quizInfo
quizInfo는 시험 문제들의 정보를 담은 배열입니다. 각 문제는 문제 유형(infoType), 시험 시기(infoTime), 문제 번호(infoNumber), 문제 내용(infoQuestion), 선택지(infoChoice), 정답(infoAnswer), 그리고 정답에 대한 설명(infoDesc)을 포함하고 있습니다.
선택자
querySelector를 사용하여 HTML 요소들을 선택하고 변수에 할당합니다. quizWrap는 시험 문제 전체를 감싸는 div, quizMainH4는 문제 유형과 시험 시기를 보여주는 h4 요소, quizTitle은 문제 번호와 문제 내용을 보여주는 div, quizQuestion은 문제 내용을 보여주는 span 요소, quizChoice는 선택지를 보여주는 ul 요소, dogWrap은 개 이미지를 감싸는 div, quizAnswer는 정답과 다음 문제로 넘어가는 버튼이 있는 div, quizDesc는 정답에 대한 설명을 보여주는 div, 그리고 quizCheck는 현재 몇 번째 문제인지와 전체 문제 수를 보여주는 span 요소입니다.
마지막으로, quizCount와 quizScore 변수를 초기화합니다. quizCount는 현재 몇 번째 문제인지를 나타내는 변수이고, quizScore는 사용자의 정답 개수를 나타내는 변수입니다.
updateQuiz는 인덱스를 매개변수로 받아서, 해당 인덱스에 대한 문제와 선택지, 정답 설명 등을 HTML 태그 형태로 반환하는 함수입니다.
- typeTag : 문제 유형과 시간 정보를 담는 HTML 태그입니다.
- questionTag : 문제 번호와 질문 내용을 담는 HTML 태그입니다.
- choiceTag : 선택지와 각 선택지의 라디오 버튼을 담는 HTML 태그입니다.
- descTag : 정답과 정답 설명을 담는 HTML 태그입니다.
- h4Tag : 남은 문제 수를 알려주는 HTML 태그입니다.
함수가 반환하는 태그들은 각각 다른 HTML 태그로 구성되어 있으며, 이들을 조합해서 전체적인 문제 형식을 만들어낼 수 있습니다.
quizWrap는 선택지가 포함된 div 요소입니다. querySelectorAll 메소드를 사용하여 선택지의 각 span 요소와 input 요소를 선택하고, setAttribute 메소드를 사용하여 onclick 이벤트를 추가하여 choiceSelected 함수가 선택된 요소를 받아오도록 합니다.
quizAnswer와 quizDesc 요소를 숨기기 위해 display 속성을 "none"으로 변경합니다.
choiceSelected 함수는 사용자가 선택한 답을 가져와서 현재 문제의 정답과 비교하고, 사용자가 맞췄는지 아닌지에 따라 개 이미지의 클래스를 변경하고 점수를 계산합니다.
quizNext는 다음 버튼을 클릭했을 때 실행되는 이벤트 리스너입니다. quizCount를 증가시키고 updateQuiz 함수를 호출하여 다음 문제를 보여줍니다. 또한 개 이미지의 클래스를 초기화합니다. 만약 현재 문제가 마지막 문제인 경우, 사용자의 점수를 계산하고 화면에 보여줍니다.