728x90
반응형
퀴즈 사이트 만들기 일곱번째 추가 정리
JAVASCRIPT
<script>
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 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; //남은 문제수
let questionTime = "";
let questionTimeRemain = "1000";
//시작하기
const startQuiz = () => {
cbtStart.classList.add("hide"); //모달창 제거
const cbtName = document.querySelector(".cbt__name");
const cbtName2 = document.querySelector(".cbt__view .name");
const valueName = cbtName2.value;
cbtName.innerHTML = valueName;
//시간 설정
questionTime = setInterval(reduceTime, 1000);
}
//데이터 가져오기
const dataQuestion = (value) => {
fetch(`https://kebab000.github.io/web2023/gineungsaJSON/${value}.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.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;
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 = () => {
// let selectValue = cbtIndex.options[cbtIndex.selectedIndex].value;
// let selectText = cbtIndex.options[cbtIndex.selectedIndex].text;
// }
// const changeSelect2 = () => {
// let selectValue = cbtIndex2.options[cbtIndex2.selectedIndex].value;
// let selectText = cbtIndex2.options[cbtIndex2.selectedIndex].text;
// }
// 문제 선택
const changeSelect = (e) => {
let selectValue = e.value;
let selectText = e.options[e.selectedIndex].text;
cbtViewSubject.innerText = selectText;
cbtHeader.innerText = selectText;
dataQuestion(selectValue);
}
// 시간 설정
const reduceTime = () => {
questionTimeRemain--;
if(questionTimeRemain == 0) endQuiz();
cbtTime.innerText = 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, 이름 입력하기
</script>
사용자가 빈칸에 입력한 이름에 따라서 수험자 이름이 바뀌게 하기
HTML 문서에서 클래스 이름이 "cbt__name"인 요소를 찾아 cbtName 변수에 할당합니다.
HTML 문서에서 클래스 이름이 "cbt__view"인 요소의 하위 요소 중 클래스 이름이 "name"인 요소를 찾아 cbtName2 변수에 할당합니다.
cbtName2 요소의 value 값을 valueName 변수에 할당합니다.
cbtName 요소의 innerHTML 속성에 valueName 변수 값을 할당합니다.
즉, 이 코드는 cbtName2 요소에서 입력된 값을 가져와 cbtName 요소의 내부 HTML 코드로 추가하는 역할을 합니다. 예를 들어, cbtName2 요소에 "John Doe"라는 이름이 입력되어 있다면, cbtName 요소의 내용은 "John Doe"가 됩니다.
여기서 중요한 것은 cbtName2 변수가 찾은 요소는 폼(form) 요소이므로 value 속성을 사용할 수 있다는 점입니다. value 속성은 폼 요소에서 입력된 값을 가져올 수 있도록 해주는 속성입니다. 이를 이용하여 cbtName2 요소에서 입력된 값을 가져와 cbtName 요소의 내용으로 추가할 수 있습니다.