어제 제작한 사이트에 이어서 몇가지의 기능을 더 추가 하였습니다.
html 코드입니다.
<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/quiz.css">
<link rel="stylesheet" href="css/reset.css">
<link href="https://unpkg.com/pattern.css" rel="stylesheet">
<!-- 파비콘 -->
<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="quizEffect05-1.html">5-1</a></li>
<li><a href="quizEffect06.html">6</a></li>
<li class="active"><a href="quizEffect07.html">7</a></li>
<li><a href="quizEffect07-1.html">7-1</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/gineungsaJC2023_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 class="cbt bad">
<div class="cbt__question"><span>2. </span>다음 빈칸을 채우시오.</div>
<div class="cbt__question__desc">객체지향 언어는 ____ 입니다.객체지향 언어는 ____ 입니다.객체지향 언어는 ____ 입니다.객체지향 언어는 ____ 입니다.객체지향 언어는 ____ 입니다.</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>
<!-- cbt__conts -->
<div class="cbt__aside">
<div class="cbt__info">
<div class="cbt__title">수험자 : <em class="cbt__name">장진용</em></div>
<div class="cbt__score">
<span>전체 문항 : <em class="cbt__length">60</em> 문항</span>
<span>남은 문항 : <em class="cbt__rest">59</em> 문항</span>
</div>
</div>
<!-- cbt__info -->
<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>
<!-- cbt__omr -->
</div>
<!-- cbt__aside -->
<div>
<div class="cbt__time">59분 10초</div>
<div class="cbt__submit">제출하기</div>
</div>
<div class="cbt__start">
<div class="cbt__modall">
<h2>기능사 시험 도전하기</h2>
<div class="cbt__choice">
<select name="cbtTime" id="cbtTime">
<option value="gineungsaJC2005_02">정보처리기능사 2005년 2회</option>
<option value="gineungsaJC2005_04">정보처리기능사 2005년 4회</option>
<option value="gineungsaJC2005_05">정보처리기능사 2005년 5회</option>
<option value="gineungsaJC2006_01">정보처리기능사 2006년 1회</option>
<option value="gineungsaJC2006_02">정보처리기능사 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_02">웹디자인기능사 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="gineungsaWD2045_01">웹디자인기능사 2014년 1회</option>
<option value="gineungsaWD2045_04">웹디자인기능사 2014년 4회</option>
<option value="gineungsaWD2045_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="minimal">확인</button>
</div>
</div>
</div>
<!-- quiz__wrap__cbt -->
</main>
모달창을 만들어 회차를 선택하면 다른 문제풀이로 넘어가는 구조를 짜두었습니다.
버튼 태그를 만들어 확인을 클릭하면 문제풀이 화면이 보이도록 하였습니다.
스크립트 코드입니다.
<script>
// let questionAll = []; //모든 퀴즈 정보
// const dataQuestion = () => {
// fetch("json/EngineerJC2023_01.json")
// .then(res => res.json())
// .then(items => {
// // console.log(item);
// questionAll = items.map((item, index) => {
// const formattedQuestion = {
// question: item.question,
// num: index + 1,
// }
// console.log(formattedQuestion);
// const answerChoices = [...item.incorrect_answers]; //(오답) answerChoices에는 틀린 답을 불러오게 변수선언함. 그리고 안에 있는 요소를 각 한개씩 따로 가져올 것이기 때문에 item.하고 불러올 값을 씀.
// formattedQuestion.answer = Math.floor(Math.random() * answerChoices.length) + 1 //(정답) 정답 랜덤으로 불러오기
// answerChoices.splice(formattedQuestion.answer -1, 0, item.incorrect_answers); //정답, 오답 합치기 (위의 두개)
// answerChoices.forEach((choice, index) => {
// formattedQuestion["choice" + (index + 1)] = choice;
// });
// });
// });
// }
// dataQuestion();
const cbtQuiz = document.querySelector(".cbt__quiz");
const cbtOmr = document.querySelector(".cbt__omr");
const cbtSubmit = document.querySelector(".cbt__submit");
const cbtInfo = document.querySelector(".cbt__info");
// const totalCount = document.querySelector(".total__count");
// const leftCount = document.querySelector(".left__count");
const cbtRest = document.querySelector(".cbt__rest")
const cbtLength = document.querySelector(".cbt__length")
const cbtStart = document.querySelector(".cbt__start");
const miniBtn = document.querySelector(".minimal")
miniBtn.addEventListener("click",() => {
cbtStart.style.display= "none";
})
let questionAll = []; // 모든 퀴즈 정보
let questionLength = 0; //전체 문제수
let questionRest = questionLength; //남은 문제수
//데이터 가져오기
const dataQuestion = () => {
fetch("json/gisa2020_01.json")
.then(res => res.json())
.then(items => {
questionAll = items.map((item, index) => {
const formattedQuestion ={
question: item.question,
number: index + 1,
}
const answerChoices = [...item.incorrect_answers]; //오답 불러오기
formattedQuestion.answer = Math.round(Math.random() * answerChoices.length) + 1; //정답을 랜덤으로 불러오기
answerChoices.splice(formattedQuestion.answer-1, 0, item.correct_answer); //정답을 랜덤으로 추가
//보기를추가
answerChoices.forEach((choice, index) => {
formattedQuestion["choice" + (index+1)] = choice;
});
//문제에 대한 해설이 있으면 출력
if(item.hasOwnProperty("question_desc")){
formattedQuestion.questionDesc = item.question_desc;
}
//문제에 대한 이미지가 있으면 출력
if(item.hasOwnProperty("question_img")){
formattedQuestion.question_img = item.question_img;
}
//해설이 있으면 출력
if(item.hasOwnProperty("question_desc")){
formattedQuestion.question_desc = item.question_desc;
}
// //전체 문항
// totalCount.innerText=items.length;
// //남은 문항
// leftCount.innerText=items.length;
return formattedQuestion;
});
newQuestion();
//전체 문제수
questionLength = questionAll.length;
cbtLength.innerHTML = questionLength;
cbtRest.innerHTML = questionLength;
})
.catch((err) => console.log(err));
}
//문제 만들기
// const updateQuiz = (index) => {
// let questionnumTag = `
// ${cbtQuiz.length}문제중에 ${cbtQuiz.length - index}문제 남았습니다
// `;
// }
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"><img src="img/${question.question_img}.jpg" alt=""></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('');
const cbtQuestionDesc = document.querySelectorAll(".cbt__question__desc")
cbtQuestionDesc.forEach(function(el){
if(el.innerHTML == "undefined"){
el.style.display = "none"
}
})
}
// 정답 확인
const answerQuiz = () => {
const cbtSelects = document.querySelectorAll(".cbt__selects");
let remainingCount = 0;
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;
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"); //보기 4개 보기가 여러개가 있으므로 querySelectAll을 이용
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"); //보기 4개 보기가 여러개가 있으므로 querySelectAll을 이용
label[answerNum[1]-1].checked = true;
const answerInputs = document.querySelectorAll(".cbt__selects input:checked");
cbtRest.innerHTML =questionLength - answerInputs.length;
}
// const answerSelect = () => {
// const answeredCount = document.querySelectorAll('input[type="radio"]:checked').length;
// const remainingCount = questionAll.length - answeredCount;
// leftCount.innerText = remainingCount;
// return remainingCount;
// }
cbtSubmit.addEventListener("click", answerQuiz);
dataQuestion();
</script>
const cbtRest = document.querySelector(".cbt__rest")
선택자로 이 부분이 추가 되어 문제를 선택하고 남은 문항수를 표현해 주도록 하였습니다.
const cbtStart = document.querySelector(".cbt__start");
const miniBtn = document.querySelector(".minimal")
선택자로 처음 화면창의 클래스로 지정된 부분과 그 안의 버튼의 클래스로 지정된 부분을 가져왔습니다.
miniBtn.addEventListener("click",() => {
cbtStart.style.display= "none";
})
addEventListener를 통해 버튼을 클릭시 처음 화면창이 사라지도록 하였습니다.
answerSelect2 함수: 객관식 문항의 보기를 선택하는 함수입니다. elem 인자로 선택된 보기의 값을 받아서 해당 보기를 체크합니다. 이 때, 선택된 보기의 번호는 _를 구분자로 사용하여 배열로 나누어 처리합니다. 또한, 선택된 보기의 문항 번호와 보기 번호를 이용하여 해당 문항의 보기를 선택합니다. 마지막으로, 선택된 보기의 개수를 통해 아직 선택되지 않은 문항의 개수를 계산하여 화면에 출력합니다.
answerSelect 함수: 주관식 문항의 보기를 선택하는 함수입니다. 사용법은 answerSelect2 함수와 동일합니다.
cbtSubmit 이벤트 리스너: 시험 제출 버튼을 클릭할 때 실행되는 함수입니다. answerQuiz 함수를 호출합니다.