“ 당신이 6개월 이상 한 번도 보지 않은 코드는 다른 사람이 다시 만드는 게 훨씬 더 나을 수 있다. ”
자바스크립트 퀴즈(Quiz) 사이트 만들기
이번에 만들어 본 퀴즈 사이트는 4월 12일에 보는 정보처리기능사 시험 대비 연습문제입니다.
한번 풀어보시고 하단에 위치한 정답 확인 버튼을 눌러 점수를 확인하세요!
퀴즈 사이트 코드
<!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>퀴즈 이펙트05</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 class="active"><a href="quizEffect05.html">5</a></li>
<li><a href="webd05-1.html">5-1</a></li>
</ul>
</header>
<!-- //header -->
<main id="main">
<div class="quiz__wrap"></div>
</main>
<!-- //main -->
이번 퀴즈 사이트 코드는 전에 만들어 본 사이트 코드들에 비하면 많이 간단하죠?
그 이유는 quiz__wrap 부분을 스크립트 코드에 넣어주었기 때문입니다.
script 코드
<script>
//문제 정보
const quizInfo = [
{
infoType : "정보처리 기능사",
infoTime : "2006년 5회",
infoNumber : "20060501",
infoQuestion : "아래의 논리 대수식을 갖는 게이트(gate)는?<br><br><img src='../assets/img/quiz_img01_01.JPG'>",
infoChoice : {
1: "NOR",
2: "AND",
3: "NAND",
4: "XOR"
},
infoAnswer: "3",
infoDesc : "<br>AND 전체에 NOT가 되어 있습니다.<br>NOT AND 이므로 NAND가 됩니다."
},{
infoType : "정보처리 기능사",
infoTime : "2006년 5회",
infoNumber : "20060502",
infoQuestion : "2진수 1011을 그레이코드(gray code)로 변환하면?",
infoChoice : {
1: "1010",
2: "0100",
3: "0111",
4: "1110"
},
infoAnswer: "4",
infoDesc : "<br>2진수를 그레이코드로 변환하는 방법은 첫번째 숫자는 그냥 내리고 나머지는 옆에것을 더해서 내려주면 됩니다."
},{
infoType : "정보처리 기능사",
infoTime : "2006년 5회",
infoNumber : "20060503",
infoQuestion : "이항(binary) 연산에 해당하는 것은?",
infoChoice : {
1: "COMPLEMENT",
2: "AND",
3: "ROTATE",
4: "SHIFT"
},
infoAnswer: "2",
infoDesc : "<br>단항연산 : ROTATE, SHIFT, MOVE, NOT(COMPLEMENT) 입니다. "
},{
infoType : "정보처리 기능사",
infoTime : "2006년 5회",
infoNumber : "20060504",
infoQuestion : "다음 그림의 연산결과는?<br><br><img src='../assets/img/quiz_img01_02.JPG'>",
infoChoice : {
1: "1010",
2: "1110",
3: "1101",
4: "1001"
},
infoAnswer: "1",
infoDesc : "<br>1110 AND 1010의 결과를 묻는 문제 입니다."
},{
infoType : "정보처리 기능사",
infoTime : "2006년 5회",
infoNumber : "20060505",
infoQuestion : "인스트럭션 레지스터(Instruction register), 부호기, 번지해독기, 제어계수기 등과 관계있는 장치는?",
infoChoice : {
1: "시프트 레지스터",
2: "범용 레지스터",
3: "베이스 레지스터",
4: "인덱스 레지스터"
},
infoAnswer: "1",
infoDesc : "<br>제어 계수기에서 힌트를 얻을수 있습니다.<br>제어장치의 일종입니다."
},{
infoType : "정보처리 기능사",
infoTime : "2006년 5회",
infoNumber : "20060506",
infoQuestion : "언어번역 프로그램(Language translator)에 해당하지 않는 것은?",
infoChoice : {
1: "컴파일러",
2: "어셈블러",
3: "인터프리터",
4: "로더"
},
infoAnswer: "4",
infoDesc : "<br>로더는 번역된 프로그램을 실행하는데 관련이 있습니다.<br>간단히 실행관련이라고 할수 있습니다."
}
];
//선택자
const quizWrap = document.querySelector(".quiz__wrap");
let quizScore = 0;
//문제 출력
//익명 화살표 함수 + forEach + push()
const updateQuiz = () => {
const exam = [];
quizInfo.forEach((question, number) => {
exam.push(`
<div class="quiz">
<div class="quiz__header">
<h2 class="quiz__title">${question.infoType} ${question.infoTime}</h2>
</div>
<div class="quiz__main ">
<div class="quiz__question">
<em>${number+1}</em>. ${question.infoQuestion}</div>
<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">
<label for="choice1${number}">
<input type="radio" id="choice1${number}" name="choice${number}" value="1">
<span>${question.infoChoice[1]}</span>
</label>
<label for="choice2${number}">
<input type="radio" id="choice2${number}" name="choice${number}" value="2">
<span>${question.infoChoice[2]}</span>
</label>
<label for="choice3${number}">
<input type="radio" id="choice3${number}" name="choice${number}" value="3">
<span>${question.infoChoice[3]}</span>
</label>
<label for="choice4${number}">
<input type="radio" id="choice4${number}" name="choice${number}" value="4">
<span>${question.infoChoice[4]}</span>
</label>
</div>
<div class="quiz__desc"> 정답은 <em>${question.infoAnswer}</em>번 입니다.${question.infoDesc}</div>
</div>
</div>
`);
});
exam.push(`
<div class="quiz__info"><b>??점</b></div>
<div class="quiz__check">💛<b>정답 확인</b>💛</div>
`);
quizWrap.innerHTML = exam.join(" ");
//설명 숨기기
document.querySelectorAll(".quiz__desc").forEach(el => el.style.display = "none");
}
updateQuiz();
//정답 확인
const answerQuiz = () => {
const quizChoices = document.querySelectorAll(".quiz__choice");
//사용자가 체크한 정답과 == 문제 정답
quizInfo.forEach((question, number) => {
const userSelector = `input[name=choice${number}]:checked`;
const quizSelectorWrap = quizChoices[number];
const userAnswer = (quizSelectorWrap.querySelector(userSelector) || {}).value;
const dogWrap = quizWrap.querySelectorAll(".dog__wrap");
if(userAnswer == question.infoAnswer){
console.log("정답");
dogWrap[number].classList.add("like");
quizScore++;
} else {
console.log("오답");
dogWrap[number].classList.add("dislike");
//
}
});
//설명 보이기
document.querySelectorAll(".quiz__desc").forEach(el => el.style.display = "block");
// 점수 보이기
document.querySelector(".quiz__info").innerHTML = Math.ceil((quizScore / quizInfo.length) * 100) + "점";
}
// 정답 클릭
document.querySelector(".quiz__check").addEventListener("click", answerQuiz);
</script>
선택자
quiz__wrap 클래스를 가진 첫 번째 요소를 선택하여 변수 quizWrap에 할당하고, 초기 점수를 저장할 변수 quizScore를 0으로 초기화해주었습니다.
문제 출력
먼저 exam이라는 빈 배열을 만들고, quizInfo 배열의 각 요소를 순회하면서 화면에 출력할 HTML 코드를 exam 배열에 추가합니다.
forEach 함수는 quizInfo 배열의 각 요소에 대해 실행되며, 콜백 함수는 각 요소와 요소의 인덱스를 인수로 받습니다. 이 콜백 함수에서는 해당 요소를 이용하여 HTML 코드를 만들어 exam 배열에 추가하고 있습니다.
만들어진 HTML 코드를 문자열로 합칠 때는 join() 함수를 사용합니다. 이 함수는 배열의 요소를 하나의 문자열로 연결해주는 역할을 합니다.
마지막으로 exam 배열에 퀴즈 총점과 정답 확인 버튼에 대한 HTML 코드를 추가하고, quizWrap이라는 HTML 요소에 만들어진 HTML 코드를 추가하여 화면에 출력합니다.
설명 숨기기
해당 코드는 먼저 HTML 문서에서 quiz__desc 클래스를 가진 모든 요소들을 선택하고, forEach 메소드를 사용하여 각각의 요소에 대해서 style.display 속성을 "none"으로 설정하는 것을 의미합니다.
즉, 이 코드는 quiz__desc 클래스를 가진 요소들의 모든 설명을 숨기는 역할을 합니다.
그 후 updateQuiz() 함수를 호출하는데, 이 함수는 해당 페이지에 퀴즈가 존재한다면, 퀴즈를 업데이트하는 역할을 합니다.
정답 확인
querySelectorAll 메소드를 사용하여, HTML 문서 내에서 .quiz__choice 클래스를 가진 모든 요소를 선택합니다. 이렇게 선택된 요소들은 NodeList 형태로 반환되며, 이를 quizChoices 변수에 저장합니다. 이후에는 quizChoices 변수를 사용하여 각 문제에 대한 선택지들을 처리할 수 있습니다.
사용자가 체크한 정답과 == 문제 정답
quizInfo 배열은 문제와 각 문제의 정답을 객체로 가지고 있습니다. forEach 메소드를 사용하여 quizInfo 배열을 반복하면서, 각 문제에 대한 선택지를 처리합니다. number 매개변수는 현재 반복 중인 문제의 인덱스를 나타내며, 이를 사용하여 input 요소의 name 속성값을 동적으로 설정합니다.
userSelector 변수는 현재 반복 중인 문제에 대해 사용자가 선택한 답안의 선택자를 저장합니다. querySelector 메소드를 사용하여 현재 반복 중인 문제의 input 요소 중에서 checked 상태인 요소를 선택합니다. 만약 해당 요소가 존재하지 않으면, 빈 객체를 생성하여 value 속성을 참조할 때 에러가 발생하지 않도록 합니다.
quizSelectorWrap 변수는 현재 반복 중인 문제에 대한 선택지를 저장합니다. quizChoices 변수는 이전에 querySelectorAll 메소드를 사용하여 선택지 요소들을 NodeList 형태로 저장한 변수입니다. number 변수를 사용하여, 현재 반복 중인 문제의 인덱스에 해당하는 선택지 요소를 선택합니다.
userAnswer 변수는 사용자가 선택한 답안의 실제 값입니다. value 속성을 참조하여 값을 가져옵니다. 만약 해당 요소가 존재하지 않는다면, 빈 객체를 생성하여 value 속성을 참조할 때 에러가 발생하지 않도록 합니다.
이후에, userAnswer 변수와 현재 반복 중인 문제의 정답(question.infoAnswer)을 비교하여, 정답인 경우 console.log("정답")을 출력하고 like 클래스를 추가하여 해당 문제의 정답으로 표시합니다. quizScore 변수도 1씩 증가시켜 정답의 개수를 저장합니다. 오답인 경우 console.log("오답")을 출력하고 dislike 클래스를 추가하여 해당 문제의 오답으로 표시합니다.
설명 보이기
document.querySelectorAll(".quiz__desc")로 선택된 모든 HTML 엘리먼트에 대해 style.display 속성을 "block"으로 변경하는 역할을 합니다.
즉, quiz__desc 클래스를 가진 모든 요소를 화면에 표시합니다. 이는 사용자가 퀴즈 문제를 푸는 과정에서 숨겨진 설명을 볼 수 있도록 합니다.
점수 보이기
querySelector()를 사용하여 quiz__info 클래스를 가진 HTML 엘리먼트를 선택하고, 이 엘리먼트의 innerHTML 속성을 변경합니다.
변경되는 내용은 사용자가 퀴즈에서 맞힌 문제의 수(quizScore)와 퀴즈 문제 전체의 수(quizInfo.length)를 이용하여 계산한 퀴즈 점수입니다. Math.ceil() 함수를 이용하여 소수점 이하를 올림하여 정수로 표시하고, 이어서 문자열로 변환하여 innerHTML에 할당합니다.
정답 클릭
querySelector()를 사용하여 "quiz__check" 클래스를 가진 HTML 엘리먼트를 선택하고, addEventListener() 메소드를 사용하여 클릭 이벤트를 감지하고, 이벤트가 발생하면 answerQuiz 함수를 실행합니다.
사용자가 퀴즈를 푸는 과정에서 "정답 확인" 버튼을 클릭할 때, answerQuiz 함수를 실행하여 사용자가 선택한 정답과 실제 정답을 비교하고, 그 결과를 출력합니다.