이번엔 객관식 문제 중 슬라이드 유형으로 작업해보겠습니다!
자바스크립트 퀴즈 이펙트(여섯 번째) 만들기
영역 지정해주기
<main id="main">
<div class="quiz__wrap">
<div class="quiz">
<div class="quiz__header">
<h2 class="quiz__title"></h2>
</div>
<div class="quiz__main">
<div class="quiz__question"></div>
<h4></h4>
<div class="quiz__view">
<div class="dog__wrap">
<div class="true">⭕정답⭕</div>
<div class="false">❌오답❌</div>
<div class="card-container">
<div class="dog">
<div class="head">
<div class="ears"></div>
<div class="face"></div>
<div class="eyes">
<div class="teardrop"></div>
</div>
<div class="nose"></div>
<div class="mouth">
<div class="tongue"></div>
</div>
<div class="chin"></div>
</div>
<div class="body">
<div class="tail"></div>
<div class="legs"></div>
</div>
</div>
</div>
</div>
</div>
<div class="quiz__choice">
<!-- <label for="choice1">
<input type="radio" id="choice1" name="choice" value="1">
<span></span>
</label>
<label for="choice2">
<input type="radio" id="choice2" name="choice" value="2">
<span></span>
</label>
<label for="choice3">
<input type="radio" id="choice3" name="choice" value="3">
<span></span>
</label>
<label for="choice4">
<input type="radio" id="choice4" name="choice" value="4">
<span></span>
</label> -->
</div>
<div class="quiz__answer">
<button class="next">다음 문제</button>
</div>
<div class="quiz__desc"></div>
<div class="quiz__info">??점</div>
<div class="quiz__check"><span>?</span>개</div>
</div>
</div>
</div>
</main>
<!-- //main -->
<footer id="footer">
<a href="mailto:yds43557340@gmail.com">yds43557340@gmail.com</a>
</footer>
<!-- //footer -->
퀴즈 이펙트 5번의 구조를 거의 참고했습니다. 다른 점은 desc 밑에 quiz__info(점수)와 quiz__check(맞힌 갯수)를 만들어주겠습니다. 그리고 문제 밑에 총 몇 문제 남았는 지를 알려주기 위해 quiz__question 밑에 h4를 넣어줍니다.
문제 정보 만들기
// 문제 정보
const quizInfo = [
{
infoType: "정보처리 기능사",
infoTime: "2007년 1회",
infoNumber: "20070101",
infoQuestion: "8bit를 1word로 이용하는 컴퓨터에서 op-code를 3bit 사용하면 인스트럭션을 몇 개 사용할 수 있는가?",
infoChoice: ["4","6","8","16"],
infoAnswer: "8",
infoDesc: "<br>op-code가 3비트란 말은 명령어부가 3비트라는 이야기 입니다.<br>3비트로 표현가능한 명령어(인스트럭션)수는 2의 3승개(2^3)는 8입니다."
},{
infoType: "정보처리 기능사",
infoTime: "2007년 1회",
infoNumber: "20070102",
infoQuestion: "중앙처리장치의 제어 부분에 의해서 해독되어 현재 실행중인 명령어를 기억하는 레지스터는?",
infoChoice: ["PC(Program Counter)","IR(Instruction Register)","MAR(Memory Address Register)","MBR(Memory Buffer Register)"],
infoAnswer: "IR(Instruction Register)",
infoDesc: "<br>명령어를 기억하는 레지스터는 IR(Instruction Register, 명령어레지스터)입니다."
},{
infoType: "정보처리 기능사",
infoTime: "2007년 1회",
infoNumber: "20070103",
infoQuestion: "번지(address)로 지정된 저장위치(storage locations)의 내용이 실제 번지가 되는 주소지정번지는?",
infoChoice: ["간접지정번지","완전지정번지","절대지정번지","상대지정번지"],
infoAnswer: "간접지정번지",
infoDesc: "<br>번지가 실제 내용의 번지가 되므로 메모리 참조회수 2회, 간접주소지정방식 입니다."
},{
infoType: "정보처리 기능사",
infoTime: "2007년 1회",
infoNumber: "20070104",
infoQuestion: "전가산기(full adder)는 어떤 회로로 구성되는가?",
infoChoice: ["반가산기 1개와 OR 게이트로 구성된다.","반가산기 1개와 AND 게이트로 구성된다.","반가산기 2개와 OR 게이트로 구성된다.","반가산기 2개와 AND 게이트로 구성된다."],
infoAnswer: "반가산기 2개와 OR 게이트로 구성된다.",
infoDesc: "<br>전가산기는 반가산기 2개 + OR 게이트 1개로 구성 됩니다."
},{
infoType: "정보처리 기능사",
infoTime: "2007년 1회",
infoNumber: "20070105",
infoQuestion: "명령어(Instructions) 형식에서 첫 번째 바이트의 기능이 아닌 것은?",
infoChoice: ["자료의 주소지정 기능","제어 기능","자료전달 기능","함수연산 기능"],
infoAnswer: "자료의 주소지정 기능",
infoDesc: "<br>명령어 = 명령어 코드부 + 명령어 주소부로 구성됩니다.<br> 첫번째 바이트이므로 명령과 관련된 내용이 기록되는데,주소 지정은 주소부에서 합니다. "
},{
infoType: "정보처리 기능사",
infoTime: "2007년 1회",
infoNumber: "20070106",
infoQuestion: "컴퓨터시스템의 중앙처리장치를 구성하는 하나의 회로로서 산술 및 논리연산을 수행하는 장치는?<br><img style='width:300px' src=''>",
infoChoice: ["Arithmetic Logic Unit","Memory Unit","I/O Unit","Associative Memory Unit"],
infoAnswer: "Arithmetic Logic Unit",
infoDesc: "<br>Arithmetic: 산술 / Logic: 논리 / Unit: 장치"
}
];
quizInfo에 배열을 만들어 문제 정보들을 넣어줍니다. 간단하게 6개 정도 넣어줍니다. 저번과 다른 점은 infoChoice에 보기를 객체로 저장했다면, 이번엔 배열로 저장해보겠습니다.
또한 infoAnswer도 번호가 아닌 정답인 문자열을 넣어줍니다.
선택자 만들기
// 선택자
const quizWrap = document.querySelector(".quiz__wrap");
const quizMainH4 = quizWrap.querySelector(".quiz__main h4");
const quizTitle = quizWrap.querySelector(".quiz__title");
const quizChoice = quizWrap.querySelector(".quiz__choice");
const quizQuestion = quizWrap.querySelector(".quiz__question");
const dogWrap = quizWrap.querySelector(".dog__wrap");
const quizAnswer = quizWrap.querySelector(".quiz__answer");
const quizNext = quizWrap.querySelector(".quiz__answer .next");
const quizDesc = quizWrap.querySelector(".quiz__desc");
const quizCheck = quizWrap.querySelector(".quiz__check span");
let quizCount = 0;
let quizScore = 0;
선택자는 전과 거의 동일합니다.
quizMainH4 라는 선택자만 추가해주었습니다. 이 부분은 총 몇 문제가 남았는지 알려주기 위해 만들어준 선택자입니다.
또, quizCheck라는 선택자에 총 몇 개를 맞추었는지 알려주기 위해 quiz__check span 부분에 선택자를 만들어줍니다.
문제 출력하기
const updateQuiz = (index) => {
let typeTag = `
<span>${quizInfo[index].infoType}</sapn>
<em>${quizInfo[index].infoTime}</em>
`;
let questionTag = `
<em>${index+1}</em>.
<span>${quizInfo[index].infoQuestion}</span>
`;
let choiceTag = `
<label for="choice1">
<input type="radio" id="choice1" name="choice" value="1">
<span>${quizInfo[index].infoChoice[0]}</span>
</label>
<label for="choice2">
<input type="radio" id="choice2" name="choice" value="2">
<span>${quizInfo[index].infoChoice[1]}</span>
</label>
<label for="choice3">
<input type="radio" id="choice3" name="choice" value="3">
<span>${quizInfo[index].infoChoice[2]}</span>
</label>
<label for="choice4">
<input type="radio" id="choice4" name="choice" value="4">
<span>${quizInfo[index].infoChoice[3]}</span>
</label>
`;
let descTag = `
정답은 ${quizInfo[index].infoAnswer}입니다.<br>
${quizInfo[index].infoDesc}
`;
let h4Tag = `
총 ${quizInfo.length - index}문제 남았습니다.
`;
quizTitle.innerHTML = typeTag;
quizQuestion.innerHTML = questionTag;
quizChoice.innerHTML = choiceTag;
quizDesc.innerHTML = descTag;
quizMainH4.innerHTML = h4Tag;
// 보기 선택자
const quizChoiceSpan = quizWrap.querySelectorAll(".quiz__choice span");
const quizChoiceInput = quizWrap.querySelectorAll(".quiz__choice input");
// forEach()
// quizChoiceSpan.forEach((span, num) => {
// span.setAttribute("onclick", "choiceSelected(this)");
// });
// for문
for(let i=0; i<quizChoiceSpan.length; i++){
quizChoiceSpan[i].setAttribute("onclick", "choiceSelected(this)");
// quizChoiceInput[i].disabled = "true";
}
// 다음 버튼, 해설 숨기기
quizAnswer.style.display = "none";
quizDesc.style.display = "none";
};
updateQuiz(quizCount);
이 코드는 updateQuiz라는 함수를 정의하고 호출하는 코드입니다.
updateQuiz 함수는 index라는 매개변수를 받습니다.
updateQuiz 함수는 quizInfo 배열에서 index 번째 퀴즈 정보를 가져와서 해당 퀴즈의 제목, 문제, 선택지, 정답 및 해설을 HTML 요소로 구성하고, 이를 innerHTML 프로퍼티를 통해 해당 요소에 삽입합니다.
그리고, 선택한 보기의 스타일을 변경하고 다음 버튼과 해설을 숨깁니다.
마지막으로, quizCount 변수의 값을 index로 전달하여 함수를 호출합니다.
저번엔 push,join을 사용했다면 이번엔 Tag라는 변수를 만들어 출력시켜주었습니다. 퀴즈이펙트 5번과 6번의 형식 둘 다 많이 사용하므로 잘 이해하고 알아둡시다!
forEach()로 출력하기
// forEach()
quizChoiceSpan.forEach((span, num) => {
span.setAttribute("onclick", "choiceSelected(this)");
});
for문으로 출력하기
// for문
for(let i=0; i<quizChoiceSpan.length; i++){
quizChoiceSpan[i].setAttribute("onclick", "choiceSelected(this)");
// quizChoiceInput[i].disabled = "true";
}
setAttribute?
setAttribute 메서드는 HTML 요소의 속성 값을 설정하는 메서드입니다. 이 메서드를 사용하여 특정 HTML 요소의 속성 값을 변경할 수 있습니다.
setAttribute 메서드는 두 개의 매개변수를 받습니다. 첫 번째 매개변수는 변경할 속성의 이름이고, 두 번째 매개변수는 해당 속성에 할당할 값입니다.
객관식 선택한 값 가져오기
// 객관식 선택
function choiceSelected(answer){
let userAnswer = answer.textContent; // 사용자 정답
let currentAnswer = quizInfo[quizCount].infoAnswer; //문제 정답
if(userAnswer == currentAnswer){
dogWrap.classList.add("like");
dogWrap.classList.remove("dislike");
quizScore++;
} else {
dogWrap.classList.add("dislike");
dogWrap.classList.remove("like");
}
// 다음 버튼, 해설 나타나기
quizAnswer.style.display = "block";
quizDesc.style.display = "block";
if(quizInfo.length - quizCount == 1){
document.querySelector(".quiz__info").innerHTML = Math.ceil((quizScore / quizInfo.length) * 100) + "점";
quizCheck.innerHTML = quizScore;
}
};
이 코드는 choiceSelected 함수를 정의하는 것입니다.
choiceSelected 함수는 사용자가 선택한 보기(answer 매개변수)를 가져와서, 해당 보기의 내용을 userAnswer 변수에 할당하고, 현재 문제의 정답을 currentAnswer 변수에 할당합니다.
그 다음, userAnswer와 currentAnswer를 비교하여, 사용자가 선택한 보기가 정답과 일치하는지 확인합니다. 일치하면, dogWrap이라는 요소에 like 클래스를 추가하고, dislike 클래스를 제거하고, quizScore 변수를 1 증가시킵니다.
일치하지 않으면, like 클래스를 제거하고 dislike 클래스를 추가합니다.
그리고, 다음 버튼과 해설을 나타내기 위해 quizAnswer와 quizDesc 요소의 display 속성을 "block"으로 설정합니다.
마지막으로, 만약 퀴즈의 마지막 문제라면, 사용자의 총점을 퀴즈 점수로 계산하여 화면에 표시하고, quizCheck 요소에도 퀴즈 점수를 출력합니다.
정답 출력하기
// 정답 확인
quizNext.addEventListener("click", () => {
quizCount++;
updateQuiz(quizCount);
dogWrap.classList.remove("like", "dislike");
});
이 코드는 quizNext 버튼을 클릭하면 실행되는 콜백 함수를 정의하는 것입니다.
이 콜백 함수는 quizCount 변수를 1 증가시키고, updateQuiz 함수를 호출하여 다음 문제를 화면에 표시합니다.
그리고, dogWrap 요소에서 like 클래스와 dislike 클래스를 모두 제거하여, 이전 문제에서 추가된 스타일을 초기화합니다. 이렇게 함으로써, 새로운 문제에서 강아지 그림에 대한 반응을 초기화할 수 있습니다.
완성된 페이지와 코드보기
퀴즈 이펙트의 다른 유형 보러가기
퀴즈 이펙트 1: https://duektmf34.tistory.com/33
퀴즈 이펙트 2: https://duektmf34.tistory.com/34
퀴즈 이펙트 3: https://duektmf34.tistory.com/41
퀴즈 이펙트 4: https://duektmf34.tistory.com/47
퀴즈 이펙트 5: https://duektmf34.tistory.com/57