6번째 퀴즈 이펙트 사이트 제작입니다. 저번 시간에 이어서 다른 방식으로 퀴즈 사이트를 제작하였습니다.
한 문제씩 풀 때마다 다음 문제로 넘어가는 방식입니다.
html 코드입니다.
<!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">
</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="quizEffect05-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">
<h4></h4>
<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="next">다음 문제</button>
</div>
<div class="quiz__desc"></div>
<div class="quiz__info">??점</div>
<div class="quiz__check"><span>??</span></div>
</div>
</div>
</div>
</main>
<!-- //main -->
<footer id="footer">
<a href="mailto:ebmdols@naver.com">ebmdols@naver.com</a>
</footer>
<!-- //footer -->
</body>
</html>
quiz__main 영역에 총 몇 문제가 남았는지 표시하기 위해 quiz__main 클래스 밑으로 <h4> 태그를 넣어 주었습니다.
quiz__info와 quiz__check 이름의 div 박스는 각각 총 점수와 총 맞힌 갯수를 풀력하기 위해 넣었습니다. 또한 <span>태그를 넣었습니다.
스크립트 코드입니다.
<script>
// 문제 정보
const quizInfo = [
{
infoType: "정보처리 기능사",
infoTime: "2006년 4월2일",
infoNumber: "20060401",
infoQuestion: "현재 수행 중에 있는 명령어 코드(Code)를 저장하고 있는 임시저장 장치는?",
infoChoice: ["인덱스 레지스터(Index Register)","명령 레지스터(Instruction Register)","어큐뮬레이터(Accumulator)","메모리 레지스터(Memory Register)"],
infoAnswer: "메모리 레지스터(Memory Register)",
infoDesc: "현재 수행중인 명령어는 명령 레지스터(Instruction Register)에 저장되면 다음 수행 명령번지는 PC(프로그램카운터)에 저장 됩니다."
},{
infoType: "정보처리 기능사",
infoTime: "2006년 4월2일",
infoNumber: "20060402",
infoQuestion: "입력된 2개의 값들 중에서 어느 것이라도 참 값을 가지고 있으면 참이라는 결과를 출력하는 논리 연산 자는?",
infoChoice: ["NOT","OR","AND","NAND"],
infoAnswer: "NAND",
infoDesc: "둘중 하나라도 참이면 참이므로 OR 입니다.<br>NAND 게이트는 두 개의 입력(A와 B)을 받아들이고, 두 입력이 모두 참(true)이면(false), 결과로 거짓(false)을 출력하며, 그 외에는 참(true)을 출력합니다."
},{
infoType: "정보처리 기능사",
infoTime: "2006년 4월2일",
infoNumber: "20060403",
infoQuestion: "다음 그림의 논리회로에서 출력 (C)은? (단, A=1, B=1이다.)<br><img src='img/20060403.jpg' alt='20060403'>",
infoChoice: ["0","1","11","10"],
infoAnswer: "10",
infoDesc: "상단부분 A와 B의 OR 게이트로 둘중의값이 하나만 참이여도 1. 하단부분 A B의 AND 게이트로 둘중의값이 모두 참이여야 1. 대입값이 둘다 1. 마지막 NAND게이트로 반댓값"
},{
infoType: "정보처리 기능사",
infoTime: "2006년 4월2일",
infoNumber: "20060404",
infoQuestion: "2진수 0110을 그레이 코드로 변환하면?",
infoChoice: ["0010","0111","0101","1110"],
infoAnswer: "1110",
infoDesc: "2진수를 그레이 코드로 변환하는 방법은 첫숫자는 그냥 내리고 나머지는 옆에숫자를 더해서 내려 주면 됩니다."
},{
infoType: "정보처리 기능사",
infoTime: "2006년 4월2일",
infoNumber: "20060405",
infoQuestion: "연산 후 입력 자료가 변하지 않고 보존되는 특징의 장점을 갖는 인스트럭션 형식은?",
infoChoice: ["0-주소 인스트럭션","1-주소 인스트럭션","2-주소 인스트럭션","3-주소 인스트럭션"],
infoAnswer: "3-주소 인스트럭션",
infoDesc: "3주소 : 연산후 입력 자료가 변하지 않음 , 2주소 : 연산후 입력 자료가 변함"
},{
infoType: "정보처리 기능사",
infoTime: "2006년 4월2일",
infoNumber: "20060406",
infoQuestion: "주소부분에 있는 값이 실제 데이터가 있는 실제 기억 장치 내의 주소를 나타내며 단순한 변수 등을 액세스하는데 사용되는 주소 지정 방식은?",
infoChoice: ["상대 Address","절대 Address","간접 Address","직접 Address"],
infoAnswer: "직접 Address",
infoDesc: "단순 변수등을 엑세스 하므로 직접주소방식 입니다."
}
];
// 선택자
const quizWrap = document.querySelector(".quiz__wrap");
const quizNumcount = document.querySelector(".quiz__main h4");
const quizTitle = quizWrap.querySelector(".quiz__title");
const quizChoice = quizWrap.querySelector(".quiz__choice");
const quizQuestion = quizWrap.querySelector(".quiz__question");
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")
let quizCount = 0;
let quizScore = 0;
// 문제 출력
const updateQuiz1 = (index, number) => {
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 countTag = `
총 ${quizInfo.length-[index]}문제 남았습니다.
`;
quizTitle.innerHTML = typeTag;
quizQuestion.innerHTML = questionTag;
quizChoice.innerHTML = choiceTag;
quizDesc.innerHTML = descTag;
quizNumcount.innerHTML = countTag;
// 보기 선택자
const quizChoiceSpan = quizWrap.querySelectorAll(".quiz__choice span");
const quizChoiceInput= quizWrap.querySelectorAll(".quiz__choice input");
// quizChoiceSpan.forEach((span, num) => {
// span.setAttribute("onclick", "choiceSelected(this)");
// })
for(let i=0; i<quizChoiceSpan.length; i++){
quizChoiceSpan[i].setAttribute("onclick", "choiceSelected(this)");
// quizChoiceInput[i].disabled = "true";
}
// 다음 버튼, 해설 숨기기
quizAnswer.style.display = "none";
quizDesc.style.display = "none";
// 총 문제
// 정답 확인 갯수
};
updateQuiz1(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.add("dislike");
dogWrap.classList.remove("like");
}
//다음 버튼, 해설 나타내기
quizAnswer.style.display = "block";
quizDesc.style.display = "block";
if(quizInfo.length - quizCount == 1){
document.querySelector(".quiz__info").innerHTML = Math.ceil((quizScore/quizInfo.length*100)) + "점";
document.querySelector(".quiz__check span").innerHTML = "맞힌 갯수 " + quizScore + "개";
}
}
// 정답 확인
quizNext.addEventListener("click", () => {
quizCount++;
updateQuiz1(quizCount);
dogWrap.classList.remove("like", "dislike");
});
</script>
// 선택자 부분
- quizCount: 현재 퀴즈 질문을 추적하는 카운터 변수입니다.
- quizScore: 사용자의 퀴즈 점수를 추적하는 변수입니다.
// 문제 출력 부분
updateQuiz1이라는 함수를 정의하는 코드입니다. 이 함수는 퀴즈를 업데이트하기 위한 정보를 사용하여 퀴즈의 question, 선택지, 정답, 힌트 및 문제 수 등을 HTML 태그로 만들어 반환합니다.
- index: 퀴즈의 인덱스(몇 번째 퀴즈인지)를 나타내는 매개변수입니다.
- number: 문제 번호를 나타내는 매개변수입니다.
함수 내부에서는 typeTag, questionTag, choiceTag, descTag, countTag 라는 변수들이 각각 문자열로 정의됩니다. 이들 문자열은 각각 퀴즈 정보에서 필요한 내용들을 HTML 태그 형태로 만들기 위해 사용됩니다.
- typeTag: 퀴즈 유형과 소요 시간을 나타내는 HTML 태그입니다.
- questionTag: 퀴즈의 질문을 나타내는 HTML 태그입니다.
- choiceTag: 퀴즈의 선택지를 나타내는 HTML 태그입니다.
- descTag: 퀴즈의 정답과 힌트를 나타내는 HTML 태그입니다.
- countTag: 퀴즈에서 남은 문제 수를 나타내는 HTML 태그입니다.
이 변수들은 템플릿 리터럴(백틱()으로 묶인) 형태로 정의되어 있으며, HTML 태그를 생성하기 위해 퀴즈 정보 객체(quizInfo`)의 특정 프로퍼티들을 참조합니다. 마지막으로, 이 함수는 이 변수들을 조합하여 퀴즈를 업데이트하는 데 필요한 HTML 코드를 반환합니다.
// 객관식 선택
choiceSelected라는 함수를 정의하는 코드입니다. 이 함수는 사용자가 선택한 답을 확인하고, 선택한 답이 정답인지 확인하여 점수를 부여하는 기능을 합니다.
- answer: 사용자가 선택한 선택지(<span>)의 DOM 요소입니다.
- userAnswer: 사용자가 선택한 선택지의 내용입니다. 이는 answer 요소의 textContent 속성으로부터 추출됩니다.
- currentAnswer: 현재 문제의 정답입니다. 이는 quizInfo 객체에서 현재 퀴즈 번호(quizCount)에 해당하는 객체의 infoAnswer 프로퍼티로부터 추출됩니다.
함수 내부에서는 userAnswer와 currentAnswer를 비교하여 사용자가 선택한 답이 정답인지 확인합니다. 사용자가 선택한 답이 정답일 경우, quizScore 변수에 1을 더하고, dogWrap 요소에 like 클래스를 추가하고 dislike 클래스를 제거합니다. 선택한 답이 정답이 아닐 경우에는, dogWrap 요소에 dislike 클래스를 추가하고 like 클래스를 제거합니다.
이 함수는 사용자가 선택한 답이 정답인지 여부를 확인하고, 그 결과에 따라 점수와 UI를 업데이트하는 중요한 기능을 합니다.
if(quizInfo.length - quizCount == 1){
document.querySelector(".quiz__info").innerHTML = Math.ceil((quizScore/quizInfo.length*100)) + "점";
document.querySelector(".quiz__check span").innerHTML = "맞힌 갯수 " + quizScore + "개";
}
현재 진행 중인 퀴즈가 마지막 문제인지를 검사하고, 만약 마지막 문제일 경우에는 quiz__info 요소와 quiz__check 요소의 내용을 업데이트합니다.
- quizInfo.length - quizCount == 1: 현재 진행 중인 문제 번호(quizCount)와 총 문제 수(quizInfo.length)를 비교하여, 현재 진행 중인 문제가 마지막 문제인지 검사합니다.
- document.querySelector(".quiz__info").innerHTML: 마지막 문제일 경우, quiz__info 클래스를 가진 요소의 내용을 업데이트합니다.
- Math.ceil((quizScore/quizInfo.length*100)): 정답률을 계산하여, 반올림한 값을 문자열 형태로 반환합니다.
- document.querySelector(".quiz__check span").innerHTML: 마지막 문제일 경우, quiz__check 클래스를 가진 요소의 내용을 업데이트합니다. 이 경우, quizScore 변수를 사용하여 사용자가 맞힌 문제 수를 표시합니다.
quizNext.addEventListener("click", () => {
quizCount++;
updateQuiz1(quizCount);
dogWrap.classList.remove("like", "dislike");
});
이 코드는 "다음" 버튼(quizNext)을 클릭했을 때, 실행되는 이벤트 핸들러입니다.
- quizCount++: 다음 문제를 풀기 위해 quizCount 변수의 값을 1 증가시킵니다.
- updateQuiz1(quizCount): updateQuiz1 함수를 호출하여, 다음 문제에 대한 정보를 화면에 업데이트합니다.
- dogWrap.classList.remove("like", "dislike"): 이전 문제에서 추가된 강아지 이미지의 클래스(like 또는 dislike)를 삭제하여, 다음 문제에 대한 강아지 이미지를 보이지 않게 합니다.