어제에 이어서 오늘도 제작중인 사이트에 기능을 추가하였습니다.
타이머 기능에 ??분 ??초가 나오도록 추가 하였고, 이용자가 모달창의 이름 입력란에 이름을 입력하면 omr창의 윗쪽에 이용자의 이름이 나오도록 하는 기능과 답을 제출하면 점수가 나오는 기능을 추가하였습니다.
??분 ??초에서 초의 앞자리가 10미만이 되면 십의 자리에 0을 추가하기
const displayTime = () => {
if(questionTimeRemain <= 0){
return "0분 00초";
} else {
let minutes = Math.floor(questionTimeRemain / 60)
let seconds = questionTimeRemain % 60;
if(seconds < 10){
return minutes + "분 " +"0"+ seconds + "초";
}
return minutes + "분 " + seconds + "초";
시간이 표시 되도록 짜여진 코드는 초가 10미만이 되면 0이 표시되지 않는 문제가 있었습니다. if문을 추가해서 초가 10미만이 되면 분과 초 사이에 0을 추가가 되도록 설정하였습니다.
사용자의 이름을 입력받아 정해진 영역에 출력하기
const cbtName = document.querySelector(".cbt__name")
const cbtViewName = document.querySelector(".cbt__view input")
// 시작하기
const startQuiz = () => {
const value = cbtViewName.value;
cbtName.innerHTML = value;
}
value는 input 요소의 값을 가져옵니다.
모달창 부분의 이름 입력란의 선택자는 cbtViewName, omr 창 부분의 이용자 이름이 들어갈 영역은 cbtName으로 지정하였습니다. 시작하기 코드 안에 변수를 설정하고 input 태그인 cbtViewName의 요소값을 가져옵니다. 그 값을 받아 cbtName이 위치한 영역에 사용자가 입력한 정보가 출력이 되도록 하였습니다.
문제를 다 푼 뒤 점수 출력하기
let quizScore = 0;
let questionAll = [];
//정답 확인
questionAll.forEach((question, number) => {
const answerQuiz = () => {
if(numberAnswer == question.answer){
console.log("정답")
cbtSelects[number].parentElement.classList.add("good")
quizScore++;
} else {
console.log("오답")
cbtSelects[number].parentElement.classList.add("bad")
//오답일 경우 정답 표시
const label = cbtSelects[number].querySelectorAll("label")
label[question.answer-1].classList.add("correct");
}
}
document.querySelector(".finish__score").innerHTML = Math.ceil((quizScore/questionAll.length*100)) + "점";
});
Math.ceil() 함수는 인자로 전달된 숫자를 올림하여 정수값으로 반환합니다.
Math속성을 이용하여 미리 정한 위치에 출력하는 방법은 저번과 같습니다. 정답을 확인하는 코드 안에 출력문을 넣고 문제가 정답인 경우 초기 값이 0인 변수 quizScore를 하나씩 증가 시켜 주어야 합니다. quizScore++를 if문의 정답 부분에 넣으면 문제를 맞출때마다 하나씩 카운트하게 됩니다. 따라서 맞춘갯수를 전체 문제정보의 갯수로 나누고 100을 곱한 뒤 올림하여 정수값만 추출합니다.
스크립트 코드입니다.
<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 cbtIndex = document.querySelector(".cbt__index")
const cbtViewSubject = document.querySelector(".cbt__view .subject");
const cbtHeader = document.querySelector(".cbt__header h2")
const miniBtn = document.querySelector(".minimal")
const cbtTime = document.querySelector(".cbt__time")
const cbtStart = document.querySelector(".cbt__start");
const cbtName = document.querySelector(".cbt__name")
const cbtViewName = document.querySelector(".cbt__view input")
miniBtn.addEventListener("click",() => {
cbtStart.style.display= "none";
})
let quizScore = 0;
let questionAll = []; // 모든 퀴즈 정보
let questionLength = 0; //전체 문제수
let questionRest = questionLength; //남은 문제수
let questionTime = "";
let questionTimeRemain = "1000";
// 시작하기
const startQuiz = () => {
cbtStart.classList.add("hide"); //모달창 제거
const value = cbtViewName.value;
cbtName.innerHTML = value;
//시간 설정
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;
}
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 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")
quizScore++;
} 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")
}
document.querySelector(".finish__score").innerHTML = Math.ceil((quizScore/questionAll.length*100)) + "점";
});
}
//보기 체크
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 changeSelect = (e) => {
let selectValue = e.value;
let selectText = e.options[cbtIndex.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;
if(seconds < 10){
return minutes + "분 " +"0"+ seconds + "초";
}
return minutes + "분 " + seconds + "초";
//초의 단위가 한자리 수가 되면 앞에 0을 붙여주기
}
}
//시험 끝
const endQuiz = () => {
alert("시험이 끝났습니다.")
}
miniBtn.addEventListener("click", startQuiz);
cbtSubmit.addEventListener("click", answerQuiz);
</script>