오늘은 퀴즈 이펙트 다섯 번째를 작업해보겠습니다!
네 번째에서는 객관식 유형을 다뤘다면, 이번에는 여러 개의 객관식 유형을 해보겠습니다!
자바스크립트 퀴즈 이펙트(다섯 번째) 만들기
영역 지정해주기
<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">
</head>
<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>
<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">
<input type="radio" id="choice1" name="choice" value="1">
<span></span>
</label>
<label for="choice2">
<input type="radio" id="choice2" name="choice" value="2">
<span></span>
</label>
<label for="choice3">
<input type="radio" id="choice3" name="choice" value="3">
<span></span>
</label>
<label for="choice4">
<input type="radio" id="choice4" name="choice" value="4">
<span></span>
</label>
</div>
<div class="quiz__answer">
<button class="confirm">정답 확인하기</button>
</div>
<div class="quiz__desc"></div>
</div>
</div>
</div>
</main>
<!-- //main -->
<footer id="footer">
<a href="mailto:yds43557340@gmail.com">yds43557340@gmail.com</a>
</footer>
<!-- //footer -->
네 번째 유형과 동일한 구조로 가져왔습니다. label을 만들어 choice 즉, 보기를 4개 만듭니다.
문제 정보 만들기
안에 들어가는 문제 정보를 입력해주겠습니다.
이번에 정보처리 기능사 기출 60문제를 내보겠습니다.
const quizInfo = [
{
infoType: "정보처리 기능사",
infoTime: "2007년 1회",
infoNumber: "20070101",
infoQuestion: "8bit를 1word로 이용하는 컴퓨터에서 op-code를 3bit 사용하면 인스트럭션을 몇 개 사용할 수 있는가?",
infoChoice: {
1: "4",
2: "6",
3: "8",
4: "16"
},
infoAnswer: "3",
infoDesc: "<br>op-code가 3비트란 말은 명령어부가 3비트라는 이야기 입니다.<br>3비트로 표현가능한 명령어(인스트럭션)수는 2의 3승개(2^3)는 8입니다."
},{
infoType: "정보처리 기능사",
infoTime: "2007년 1회",
infoNumber: "20070102",
infoQuestion: "중앙처리장치의 제어 부분에 의해서 해독되어 현재 실행중인 명령어를 기억하는 레지스터는?",
infoChoice: {
1: "PC(Program Counter)",
2: "IR(Instruction Register)",
3: "MAR(Memory Address Register)",
4: "MBR(Memory Buffer Register)"
},
infoAnswer: "2",
infoDesc: "<br>명령어를 기억하는 레지스터는 IR(Instruction Register, 명령어레지스터)입니다."
},{
infoType: "정보처리 기능사",
infoTime: "2007년 1회",
infoNumber: "20070103",
infoQuestion: "번지(address)로 지정된 저장위치(storage locations)의 내용이 실제 번지가 되는 주소지정번지는?",
infoChoice: {
1: "간접지정번지",
2: "완전지정번지",
3: "절대지정번지",
4: "상대지정번지"
},
infoAnswer: "1",
infoDesc: "<br>번지가 실제 내용의 번지가 되므로 메모리 참조회수 2회, 간접주소지정방식 입니다."
},{
infoType: "정보처리 기능사",
infoTime: "2007년 1회",
infoNumber: "20070104",
infoQuestion: "전가산기(full adder)는 어떤 회로로 구성되는가?",
infoChoice: {
1: "반가산기 1개와 OR 게이트로 구성된다.",
2: "반가산기 1개와 AND 게이트로 구성된다.",
3: "반가산기 2개와 OR 게이트로 구성된다.",
4: "반가산기 2개와 AND 게이트로 구성된다."
},
infoAnswer: "3",
infoDesc: "<br>전가산기는 반가산기 2개 + OR 게이트 1개로 구성 됩니다."
}
];
quizInfo라는 변수에 문제 정보들을 배열과 객체 안에 넣어줍니다.
선택자 만들기
const quizWrap = document.querySelector(".quiz__wrap");
let quizScore = 0;
quizWrap 선택자를 만들어줍니다.
그리고 총 몇 개를 맞췄는지 점수를 표현해주기 위해 quizScore라는 변수를 선언해줍니다.
문제 출력하기
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>번 입니다.<br>${question.infoDesc}</div>
</div>
</div>
`);
});
exam.push(`
<div class="quiz__info">??점</div>
<div class="quiz__check">🌹<b>정답 확인</b>🌹</div>
`);
quizWrap.innerHTML = exam.join(" ");
// 설명 숨기기
document.querySelectorAll(".quiz__desc").forEach(el => el.style.display = "none");
}
updateQuiz();
화살표 함수를 사용해 updateQuiz 를 출력시켜주겠습니다.
updateQuiz() 함수는 먼저 빈 배열 exam을 생성하고, quizInfo 배열을 순회하며 각각의 question 객체를 사용하여 HTML 문자열을 생성하고 exam 배열에 추가합니다.
이때 quizInfo 배열의 각 요소에는 문제와 보기, 정답, 해설 등의 정보가 담겨 있습니다.
생성된 HTML 문자열을 quizWrap 요소의 innerHTML로 설정하고, document.querySelectorAll(".quiz__desc")로 찾은 모든 요소의 display 스타일을 "none"으로 설정하여 문제 해설을 숨깁니다.
마지막으로 exam 배열에 점수와 정답 확인 버튼을 추가하고, 다시 quizWrap 요소의 innerHTML로 설정합니다.
해당 코드는 문제를 보여주는 HTML을 동적으로 생성하고 이를 웹 페이지에 렌더링하는 기능을 수행합니다.
정답 확인하기
// 정답 확인
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){
dogWrap[number].classList.add("like");
quizScore++;
} else {
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) + "점";
}
answerQuiz 함수는 퀴즈의 정답을 확인하고, 정답 여부에 따라 화면에 결과를 보여주는 기능을 수행합니다.
quizChoices 변수에 문제의 선택지가 담긴 DOM 엘리먼트를 선택합니다. document.querySelectorAll 메서드를 사용하여 선택한 엘리먼트를 NodeList 형태로 반환합니다.
quizInfo 배열에 저장된 각 문제에 대해 반복문을 수행합니다. 각 문제에 대해 사용자가 선택한 답안을 가져오고, 이를 정답과 비교합니다.
정답 여부에 따라 해당 문제의 선택지 영역에 반려견 이미지와 함께 '정답입니다!' 또는 '틀렸습니다!' 메시지를 출력합니다. quizScore 변수를 사용하여 정답일 경우 점수를 추가합니다.
모든 문제에 대해 정답 여부를 확인한 후, 설명을 보이고, 사용자의 점수를 화면에 출력합니다.
즉, 해당 코드는 퀴즈를 수행하는 웹 페이지에서 "정답 확인" 버튼을 누르면 호출되며, 사용자가 선택한 답안을 확인하고, 정답 여부에 따라 결과를 보여주는 기능을 수행합니다.
정답 표시하기
exam.push(`
<div class="quiz__info">??점</div>
<div class="quiz__check">🌹<b>정답 확인</b>🌹</div>
`);
quizWrap.innerHTML = exam.join(" ");
아까 설정해준 quiz__info와 quiz__check를 설정해주겠습니다.
document.querySelector(".quiz__check").addEventListener("click", answerQuiz);
선택자를 통해 quiz__check를 클릭했을 때 addEventListener를 통해 answerQuiz가 출력될 수 있도록 해줍니다.
완성된 페이지와 코드 보기
퀴즈 이펙트의 다른 유형 보러가기
퀴즈 이펙트 1: https://duektmf34.tistory.com/33
퀴즈 이펙트 2: https://duektmf34.tistory.com/34
퀴즈 이펙트 3: https://duektmf34.tistory.com/41
퀴즈 이펙트 4: https://duektmf34.tistory.com/47