오늘은 어제 만든 유형에서 조금 더 추가하여 만들어 보았습니다.
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>퀴즈 이펙트07</title>
<link rel="stylesheet" href="css/reset.css">
<link rel="stylesheet" href="css/quiz.css">
<!-- 파비콘 -->
<link rel="shortcut icon" type="image/x-icon" href="img/favicon.png"/>
<link rel="apple-touch-icon" sizes="114x114" href="img/favicon.png"/>
<link rel="apple-touch-icon" href="img/favicon.png"/>
</head>
<body>
<header id="header">
<h1><a href="../javascript14.html">Quiz</a> <em>객관식 확인 CBT 카드 유형</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="quizEffect06.html">6</a></li>
<li class="active"><a href="quizEffect07.html">7</a></li>
</ul>
</header>
<!-- //header -->
<main id="main">
<div class="quiz__wrap__cbt">
<div class="cbt__header">
<h2>2020년 1회 정보처리기능사 기출문제</h2>
</div>
<div class="cbt__conts">
<div class="cbt__quiz">
<!-- <div class="cbt good">
<div class="cbt__question"><span>1</span>. 객체지향 프로그램에서 데이터를 추상화하는 단위는?</div>
<div class="cbt__question__img"><img src="img/gineungsaWD2023_01_01.jpg" alt="기능사"></div>
<div class="cbt__selects">
<input type="radio" id="select1">
<label for="select1"><span>클래스</span></label>
<input type="radio" id="select2">
<label for="select2"><span>메소드</span></label>
<input type="radio" id="select3">
<label for="select3"><span>상속</span></label>
<input type="radio" id="select4">
<label for="select4"><span>메시지</span></label>
</div>
<div class="cbt__desc">객체지향언어는 이다. 객체지향언어는 이다. 객체지향언어는 이다. 객체지향언어는 이다. 객체지향언어는 이다. 객체지향언어는 이다.</div>
<div class="cbt__keyword">객체지향언어</div>
</div> -->
</div>
</div>
<div class="cbt__aside">
<div class="cbt__info">
<div>
<button class="cbt__submit">제출하기</button>
<span class="cbt__time">59분 10초</span>
</div>
<div>
<div class="cbt__title">수험자 : <em class="cbt__name">이승연</em></div>
<div class="cbt__score">
<span>전체 문제수 : <em class="cbt__length">0</em>문항</span>
<span>남은 문제수 : <em class="cbt__rest">0</em>문항</span>
</div>
</div>
</div>
<div class="cbt__omr">
<!-- <div class="omr">
<strong>1</strong>
<input type="radio" id="omr0_1">
<label for="omr0_1">
<span class="label-inner">1</span>
</label>
<input type="radio" id="omr0_2">
<label for="omr0_2">
<span class="label-inner">2</span>
</label>
<input type="radio" id="omr0_3">
<label for="omr0_3">
<span class="label-inner">3</span>
</label>
<input type="radio" id="omr0_4">
<label for="omr0_4">
<span class="label-inner">4</span>
</label>
</div> -->
</div>
</div>
<div class="cbt__start">
<div class="cbt__modal1">
<h2>기능사 시험 도전하기</h2>
<div class="cbt__choice">
<select name="cbtTime" id="cbtTime">
<option value="gineungsaJC2005_02">정보처리기능사 2005년 2회</option>
<option value="gineungsaJC2005_05">정보처리기능사 2005년 4회</option>
<option value="gineungsaJC2005_05">정보처리기능사 2005년 5회</option>
<option value="gineungsaJC2006_01">정보처리기능사 2006년 1회</option>
<option value="gineungsaJC2006_03">정보처리기능사 2006년 2회</option>
<option value="gineungsaJC2006_03">정보처리기능사 2006년 3회</option>
<option value="gineungsaJC2006_05">정보처리기능사 2006년 5회</option>
<option value="gineungsaJC2007_01">정보처리기능사 2007년 1회</option>
<option value="gineungsaJC2007_02">정보처리기능사 2007년 2회</option>
<option value="gineungsaJC2007_05">정보처리기능사 2007년 5회</option>
<option value="gineungsaJC2008_01">정보처리기능사 2008년 1회</option>
<option value="gineungsaJC2008_02">정보처리기능사 2008년 2회</option>
<option value="gineungsaJC2008_04">정보처리기능사 2008년 4회</option>
<option value="gineungsaJC2008_05">정보처리기능사 2008년 5회</option>
<option value="gineungsaJC2009_01">정보처리기능사 2009년 1회</option>
<option value="gineungsaJC2009_05">정보처리기능사 2009년 5회</option>
<option value="gineungsaJC2010_02">정보처리기능사 2010년 2회</option>
<option value="gineungsaJC2010_05">정보처리기능사 2010년 5회</option>
<option value="gineungsaJC2011_01">정보처리기능사 2011년 1회</option>
<option value="gineungsaJC2011_02">정보처리기능사 2011년 2회</option>
<option value="gineungsaJC2011_04">정보처리기능사 2011년 4회</option>
<option value="gineungsaJC2011_05">정보처리기능사 2011년 5회</option>
</select>
<select name="cbtTime" id="cbtTime">
<option value="gineungsaWD2009_05">웹디자인기능사 2009년 5회</option>
<option value="gineungsaWD2010_01">웹디자인기능사 2010년 1회</option>
<option value="gineungsaWD2010_02">웹디자인기능사 2010년 2회</option>
<option value="gineungsaWD2010_04">웹디자인기능사 2010년 4회</option>
<option value="gineungsaWD2010_05">웹디자인기능사 2010년 5회</option>
<option value="gineungsaWD2011_01">웹디자인기능사 2011년 1회</option>
<option value="gineungsaWD2011_02">웹디자인기능사 2011년 2회</option>
<option value="gineungsaWD2011_04">웹디자인기능사 2011년 4회</option>
<option value="gineungsaWD2011_05">웹디자인기능사 2011년 5회</option>
<option value="gineungsaWD2012_02">웹디자인기능사 2012년 2회</option>
<option value="gineungsaWD2012_04">웹디자인기능사 2012년 4회</option>
<option value="gineungsaWD2012_05">웹디자인기능사 2012년 5회</option>
<option value="gineungsaWD2013_02">웹디자인기능사 2013년 2회</option>
<option value="gineungsaWD2013_04">웹디자인기능사 2013년 4회</option>
<option value="gineungsaWD2013_05">웹디자인기능사 2013년 5회</option>
<option value="gineungsaWD2014_01">웹디자인기능사 2014년 1회</option>
<option value="gineungsaWD2014_04">웹디자인기능사 2014년 4회</option>
<option value="gineungsaWD2014_05">웹디자인기능사 2014년 5회</option>
<option value="gineungsaWD2015_01">웹디자인기능사 2015년 1회</option>
<option value="gineungsaWD2015_03">웹디자인기능사 2015년 3회</option>
<option value="gineungsaWD2015_04">웹디자인기능사 2015년 4회</option>
<option value="gineungsaWD2015_05">웹디자인기능사 2015년 5회</option>
<option value="gineungsaWD2016_01">웹디자인기능사 2016년 1회</option>
<option value="gineungsaWD2016_04">웹디자인기능사 2016년 4회</option>
</select>
</div>
<button class='start__button'>시작하기</button>
</div>
</div>
</div>
</main>
<!-- //main -->
<!-- <footer id="footer">
<a href="mailto:1346zany@gmail.com">1346zany@gmail.com</a>
</footer> -->
<!-- //footer -->
</body>
</html>
modal을 통해 팝업창을 만들어주고 그 안에 select를 추가해 다른 기능사를 선택할 수 있는 선택창을 만들어 주었습니다.
그리고 아래에 시작하기 버튼을 만들어주었습니다.
script
시작버튼 누르기
starButton.addEventListener("click",() => {
cbtStart.style.display = "none";
});
먼저, modal 창에서 시작하기 버튼을 누르면 시험 화면이 나타나도록 하기 위해 클릭했을때 display=none을 해주었습니다.
문제 만들기
//문제 만들기
const newQuestion = () => {
const exam = [];
const omr = [];
questionAll.forEach((question, number) => {
exam.push(`
<div class="cbt">
<div class="cbt__question"><span>${question.number}</span>. ${question.question}</div>
<div class="cbt__question__img">${question.question_img}</div>
<div class="cbt__question__desc">${question.question_desc}</div>
<div class="cbt__selects">
<input type="radio" id="select${number}_1" name="select${number}" value="${number}_1" onclick="answerSelect2(this)">
<label for="select${number}_1"><span>${question.choice1}</span></label>
<input type="radio" id="select${number}_2" name="select${number}" value="${number}_2" onclick="answerSelect2(this)">
<label for="select${number}_2"><span>${question.choice2}</span></label>
<input type="radio" id="select${number}_3" name="select${number}" value="${number}_3" onclick="answerSelect2(this)">
<label for="select${number}_3"><span>${question.choice3}</span></label>
<input type="radio" id="select${number}_4" name="select${number}" value="${number}_4" onclick="answerSelect2(this)">
<label for="select${number}_4"><span>${question.choice4}</span></label>
</div>
<div class="cbt__desc hide">${question.desc}</div>
</div>
`);
omr.push(`
<div class="omr">
<strong>${question.number}</strong>
<input type="radio" name="omr${number}" id="omr${number}_1" value="${number}_1" onclick="answerSelect(this)">
<label for="omr${number}_1"><span class="label-inner">1</span></label>
<input type="radio" name="omr${number}" id="omr${number}_2" value="${number}_2" onclick="answerSelect(this)">
<label for="omr${number}_2"><span class="label-inner">2</span></label>
<input type="radio" name="omr${number}" id="omr${number}_3" value="${number}_3" onclick="answerSelect(this)">
<label for="omr${number}_3"><span class="label-inner">3</span></label>
<input type="radio" name="omr${number}" id="omr${number}_4" value="${number}_4" onclick="answerSelect(this)">
<label for="omr${number}_4"><span class="label-inner">4</span></label>
</div>
`)
});
cbtQuiz.innerHTML = exam.join('');
cbtOmr.innerHTML = omr.join('');
}
어제는 omr과 문제 답 체크가 각각 선택되었지만 오늘은 둘이 연동 되어 답이 체크가 될 수 있도록 value값을 같게 맞춰주고 onclick을 exam과 omr에 모두 넣어주었습니다.
answerSelect() 함수와 answerSelect2() 함수는 사용자가 선택한 답안을 처리하는 함수입니다.
answerSelect() 함수는 OMR 방식으로 선택한 경우 사용되며, answerSelect2() 함수는 라디오 버튼 방식으로 선택한 경우 사용됩니다.
정답확인
//정답 확인
const answerQuiz = () => {
const cbtSelects = document.querySelectorAll(".cbt__selects");
questionAll.forEach((question, number) => {
const quizSelectsWrap = cbtSelects[number];
const userSelector = `input[name=select${number}]:checked`;
const userAnswer = (quizSelectsWrap.querySelector(userSelector) || {}).value;
const numberAnswer = userAnswer ? userAnswer.slice(-1) : undefined;
console.log(userAnswer)
if(numberAnswer == question.answer){
console.log("정답입니다.")
cbtSelects[number].parentElement.classList.add("good");
} else{
console.log("오답입니다.")
cbtSelects[number].parentElement.classList.add("bad");
const label = cbtSelects[number].querySelectorAll("label");
label[question.answer-1].classList.add("correct")
}
const quizDesc = document.querySelectorAll(".cbt__desc");
if(quizDesc[number].innerText == "undefined"){
quizDesc[number].classList.add("hide");
} else {
quizDesc[number].classList.remove("hide")
}
});
}
//보기 체크
const answerSelect2 = (elem) => {
const answer = elem.value;
const answerNum = answer.split("_");
const select = document.querySelectorAll(".cbt__omr .omr"); //전체 문항 수 100개
const label = select[answerNum[0]].querySelectorAll("input"); //보기 100개
label [answerNum[1]-1].checked =true;
const answerInputs = document.querySelectorAll(".cbt__selects input:checked");
cbtRest.innerHTML = questionLength - answerInputs.length;
}
//보기 체크2
const answerSelect = (elem) => {
const answer = elem.value;
const answerNum = answer.split("_");
const select = document.querySelectorAll(".cbt__quiz .cbt"); //전체 문항 수 100개
const label = select[answerNum[0]].querySelectorAll("input"); //보기 100개
label [answerNum[1]-1].checked =true;
const answerInputs = document.querySelectorAll(".cbt__selects input:checked");
cbtRest.innerHTML = questionLength - answerInputs.length;
}
cbtSubmit.addEventListener("click",answerQuiz);
dataQuestion();
</script>
answerSelect2
매개변수 element로 전달된 값에서 answer로 변수 선언을 하고 보기 값을 가져옵니다.
.split("_")를 사용해 구분자 _로 구분하여 보기 번호를 분리하고, 배열로 저장합니다.
select를 선언해 .cbt__omr의 omr을 선택하여 전체 문항을 선택합니다.
label [answerNum[1]-1].checked로 보기를 선택합니다.
answerInput에 체크된 모든 문항을 선택해줍니다.
cbtRest에는 문항의 수에서 answerInput안에 넣어진 체크된 모든 문항을 빼어체크 되지 않은 남은 문제의 수를 표시합니다.
answerSelect
answerSelect2와 유사한데 cbt__quiz의 cbt를 선택해서 문제를 가져옵니다.
나머지도 유사한 이유는 omr에서 선택했을 때도 남은 문항 수가 동일하기 위함입니다.