728x90
퀴즈사이트 만들기 cbt유형
이번에는 시작화면에서 여러회차의 시험지를 풀어볼 수 있도록 (깃허브링크 연결)하며 이름을 입력해 수험자 이름이 표시되게 해줍니다. 또 타이머를 설정하여 남은시간을 표시해 줍니다.
코드블럭
선택자와 변수선언
const cbt = document.querySelectorAll(".cbt");
const cbtQuiz = document.querySelector(".cbt__quiz");
const cbtOmr = document.querySelector(".cbt__omr");
const cbtSubmit = document.querySelector(".cbt__submit");
const cbtRest = document.querySelector(".cbt__rest");
const cbtLength = document.querySelector(".cbt__length");
const cbtIndex = document.querySelector(".cbt__index");
const cbtViewSubject = document.querySelector(".cbt__view .subject");
const cbtHeader = document.querySelector(".cbt__header h2");
const cbtStartBtn = document.querySelector(".cbt__start__btn");
const cbtStart = document.querySelector(".cbt__start");
const cbtTime = document.querySelector(".cbt__time");
let questionAll = []; //모든 퀴즈 정보
let questionLength = 0; //전체 문제수
let questionRest = questionLength; //남은 문제수 //100개대신 변수를 넣어줌
let questionTime = "";
let questionTimeRemain = "1000";
시작하는 화면, 시간설정
//시작하기
const startQuiz = () => {
cbtStart.classList.add("hide"); //모달창 제거
//시간 설정
questionTime = setInterval(reduceTime, 1000);
데이터 가져오기
//데이터 가져오기
const dataQuestion = (value) => {
fetch(`https://kebab000.github.io/web2023/gineungsaJSON/${value}.json`)
// fetch("json/gineungsaJC2009_05.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.floor(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.question_desc = item.question_desc;
}
//문제에 대한 이미지가 있으면 출력
if(item.hasOwnProperty("question_img")){
formattedQuestion.question_img = item.question_img;
}
//해설이 있으면 출력
if(item.hasOwnProperty("desc")){
formattedQuestion.desc = item.desc;
}
//console.log(formattedQuestion);
return formattedQuestion;
});
newQuestion(); //문제 만들기
//전체 문제수
questionLength = questionAll.length;
cbtLength.innerHTML = questionLength;
cbtRest.innerHTML = questionLength;
})
.catch((err) => console.log(err));
}
문제 만들기
//문제 만들기
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="https://kebab000.github.io/web2023/gineungsaJPG/${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('');
//설명 없는거 제거
document.querySelectorAll(".cbt__question__desc").forEach(desc => {
if(desc.innerText ==="undefined"){
desc.classList.add("hide");
}
});
//이미지가 없는거 제거
document.querySelectorAll(".cbt__question__img").forEach(img => {
let src = img.querySelector("img").src;
if(src.includes("undefined")){
img.classList.add("hide")
}
});
}
정답만들기
//정답 확인
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;
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개
label[answerNum[1]-1].checked = true;
// console.log(answerNum[0]);
// console.log(answerNum[1]);
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개
label[answerNum[1]-1].checked = true;
const answerInputs = document.querySelectorAll(".cbt__selects input:checked");
cbtRest.innerHTML = questionLength - answerInputs.length;
}
문제선택, 시간설정및 표시, 시험이 끝났을때
//문제 선택
const changeSelect = (e) => {
let selectValue = e.value;
let selectText = e.options [e.selectedIndex].text;
cbtViewSubject.innerHTML = selectText;
cbtHeader.innerHTML = selectText;
dataQuestion(selectValue)
}
//시간설정
const reduceTime = () => {
questionTimeRemain--;
if(questionTimeRemain == 0) endQuiz();
cbtTime.innerHTML = displayTime();
}
// 시간 표시
const displayTime = () => {
if(questionTimeRemain <=0){
return "0분 00초";
} else {
let minutes = Math.floor(questionTimeRemain / 60);
let seconds = questionTimeRemain % 60;
return minutes + "분" + seconds + "초"
//초의 단위가 한자리 수가 되면 앞에 0을 붙여주기
}
}
//게임 끝
const endQuiz = () => {
alert("시험이 끝났습니다.")
}
cbtStartBtn.addEventListener("click",startQuiz);
cbtSubmit.addEventListener("click", answerQuiz);
// dataQuestion();
✨초의 단위가 한자리 수가 뒤면 앞에 0붙여주기
// 시간 표시
const displayTime = () => {
if(questionTimeRemain <=0){
return "0분 00초";
} else {
let minutes = Math.floor(questionTimeRemain / 60);
let seconds = questionTimeRemain % 60;
// 초 앞에 0을 붙이기
if (seconds < 10) {
seconds = "0" + seconds;
}
return minutes + "분 " + seconds + "초";
}
}
seconds 변수를 문자열로 변환한 후, 문자열 길이가 1인 경우 앞에 "0"을 추가해 줍니다.
위 코드에서 if 문은 seconds 변수가 10보다 작은 경우(즉, 한자리 수 초인 경우)에 seconds 변수 앞에 "0"을 추가합니다. 그리고 "분 "과 "초" 사이에 공백을 추가하여, "X분 XX초" 형태의 문자열을 반환합니다.
✨이름을 넣을 input박스의 선택자를 만들어 주고 이렵될 값을 변수로 저장합니다.
시작하는 화면에서 이름을 입력하는 창이 뜨면 input의 값을 변수로 저장해 줍니다.
선택자.innerHTML = input값의 변수를 입력하여 문제푸는 화면에 수험자 이름을 나타내 줍니다.