“ 지연되는 프로젝트에 인력을 더 투입하면 오히려 더 늦어진다. ”
- Frederick Philips Brooks
Mythical Man-Month 저자
728x90
퀴즈 이펙트 06
이번 퀴즈 이펙트 효과에서는 저번 퀴즈 효과에서 객관식으로 모든 문제들이 나타나서 하나하나 클릭해서 정답을 확인했다면 이번에는 슬라이드 형식으로 답을 선택하고 다음으로 넘겨서 한 칸 안에서 여러 문제를 넘겨서 풀고 나면 점수와 맞힌 갯수를 확인 할 수 있는 유형입니다.
HTML
<!DOCTYPE html>
<html lang="ko">
<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>퀴즈 이펙트06</title>
<link rel="stylesheet" href="css/reset.css">
<link rel="stylesheet" href="css/quiz.css">
</head>
<body>
<header id="header">
<h1><a href="../javascript14.html">Quiz</a> <em>객관식 확인하기(여러문제) 유형 : 슬라이드 유형</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 class="active"><a href="quizEffect06.html">6</a></li>
</ul>
</header>
<!--//header-->
<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>
<div class="quiz__view">
<div class='dog__wrap'>
<div class="seacrh__info">
<span></span>
</div>
<div class="ture">정답입니다!</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:jeongyouna_@naver.com">jeongyouna_@naver.com</a>
</footer>
<!-- footer -->
HTML구조
- 저번에 퀴즈 이펙트 5에서 사용한 코드를 javascript부분을 비워두고 그대로 HTML을 가져옵니다. 구조를 살펴보면
- quiz__main안에 quiz__wrap을 두고 class= quiz를 만들어 준 후 header안에 title을 지정합니다.
- class속성을 부여해서 quiz__main을 만들어서 그 안에 question과 view와 문제가 몇개 남았는지 알 수 있게끔such__info에 span태그를 추가해준 후 강아지가 나올 수 있게끔 dog__wrap의 속성들을 넣어줍니다.
- 다음은 quiz__choice 문제가 선택될 때의 구조를 만들어 주는데 동그랗게 체크 할 수 있는 부분을 만들어 주기 위해 radio 속성을 부여 해줍니다. 그리고 각자 value(값)에 숫자를 부여 해줍니다.
- 그리고 quiz__answer에서 정답을 선택하면 다음 문제로 넘어갈 수 있게끔 button 태그를 써서 "next"라는 속성을 부여해줍니다.
- 다음은 quiz__desc는 해설이 나올 수 있게끔 해주고 quiz__info에 총 점수가 나올 수 있게끔 quiz__check에 span태그를 부여해서 총 맞힌 갯수가 나올 수 있게끔 해줍니다.
추가된 CSS
.seacrh__info {
padding: 20px;
text-align: center;
font-family: 'suncheon';
font-size: 20px;
background-color: #fcf016c3;
}
- search__info가 위에서 20px떨어질 수 있게끔 설정하고 글자가 가운데에 오고 폰트와 사이즈를 지정해준 후 안에 들어갈 배경색을 지정 해 줍니다.
Javascript
<script>
//문제 정보
const quizInfo = [
{
infoType: "정보처리 기능사",
infoTime: "2011년 2회",
infoNumber: "20110201",
infoQuestion: "현재 수행 중에 있는 명령 코드(Code)를 저장하고 있는 임시 저장 장치는?",
infoChoice: ["인덱스 레지스터(Index Register)","명령 레지스터(Instrudction Register)","누산기(Accumulator)","메모리 레지스터(Memory Register)"],
infoAnswer: "명령 레지스터(Instrudction Register)",
infoDesc:"<br>명령 레지스터(Instruction Register) : 현재 실행중인 명령을 기억하는 레지스터 입니다."
},{
infoType: "정보처리 기능사",
infoTime: "2011년 2회",
infoNumber: "20110202",
infoQuestion: "다음 중 RISC(Reduced Instruction Set Computer)의 설명으로 옳은 것은?",
infoChoice:[ "메모리에 대한 액세스는 LOAD와 STORE만으로 한정되어 있다.","명령어마다 다른 수행 사이클을 가지므로 파이프라이닝이 효율적이다.","마이크로 코드에 의해 해석 후 명령어를 수행한다.","주소지정방식이 다양하게 존재한다."],
infoAnswer: "메모리에 대한 액세스는 LOAD와 STORE만으로 한정되어 있다.",
infoDesc: "<br>RISC의 약자인 Reduced는 제한된으로 해석 될 수도 있습니다.따라서 메모리에 대한 엑세스는 LOAD와 STORE만으로 한정 되어 있다에서 한정 이라는 말과 Reduced의 뜻이랑 같습니다."
},{
infoType: "정보처리 기능사",
infoTime: "2011년 2회",
infoNumber: "20110203",
infoQuestion: "클록펄스에 의해서 기억된 내용을 한 자리씩 우측이나 좌측으로 이동시키는 레지스터는?",
infoChoice: ["시프트 레지스터", "범용 레지스터", "베이스 레지스터","인덱스 레지스터"],
infoAnswer: "시프트 레지스터",
infoDesc: "<br>시프트(shift)의 뜻은 '이동시키다'로 우측이나 좌측으로 이동시키는 레지스터와 뜻이 같습니다."
},{
infoType: "정보처리 기능사",
infoTime: "2011년 2회",
infoNumber: "20110204",
infoQuestion: "중앙처리장치(CPU)에 해당하는 부분을 하나의 대규모 집적회로의 칩에 내장시켜 기능을 수행하게 하는 것은?",
infoChoice: ["마이크로프로세서","컴파일러","소프트웨어","레지스터"],
infoAnswer: "마이크로프로세서",
infoDesc: "<br>마이크로프로세서 : 중앙처리장치에 해당하는 부분을 하나의 대규모 집적회로의 칩에 내장시켜 기능을 수행하게 하는 것입니다."
},{
infoType: "정보처리 기능사",
infoTime: "2011년 2회",
infoNumber: "20110205",
infoQuestion: "다음에 실행할 명령어의 번지를 기억하는 레지스터는?",
infoChoice: ["Program Counter","Memory Address Register","Instruction Register","Processor Register",],
infoAnswer: "Instruction Register",
infoDesc: "<br>레지스터MAR : 번지(주소)<br>기억MBR : 버퍼(임시기억)<br>IR : 명령어레지스터(명령어를 읽어서 저장)<br>PC : 프로그램카운터(다음수행 명령번지 기억)<br>명령어해독기 : IR 내용 해독<br>ACC : 누산기(연산결과 일시(임시)저장)<br>데이터레지스터 : 데이터 임시저장 <br>상태 레지스터 : CPU상태 저장(PSW)<br>보수기 : 보수로 바꾸는 장치 "
},{
infoType: "정보처리 기능사",
infoTime: "2011년 2회",
infoNumber: "20110206",
infoQuestion: "8비트짜리 레지스터 A와 B에 각각 11010101과 11110000이 들어 있다. 레지스터 A의 내용이 00100101로 바뀌었다면 두 레지스터 A, B 사이에 수행된 논리연산은?",
infoChoice: ["Exclusive-OR","MAND 연산","OR 연산","NOR 연산",],
infoAnswer: "OR 연산",
infoDesc: "<br>XOR : 서로 다르면 1 같으면 0AND : 모두 1 일때만 1OR: 둘중에 한개라도 1 이면 1NOR : OR 결과와 반대, 모두 0 일때만 1"
}
];
문제정보
- 퀴즈 이펙트 5번에서 가져와서 const quizInfo = 로 문제 정보들을 작성합니다.
- 객체로 있던 내용들을 [ ] 변수를 사용해서 넣어줍니다.
- 문제는 6문제를 만들어 줍니다.
//선택자
const quizWrap = document.querySelector(".quiz__wrap");
const quizTitle = quizWrap.querySelector(".quiz__title");
const quizChoice = quizWrap.querySelector(".quiz__choice");
const quizQuestion = quizWrap.querySelector(".quiz__question");
// document.querySelector(".quiz__title").innerHTML = quizInfo[0].infoType
// document.querySelector(".quiz__title").innerHTML = quizInfo[0].infoTime
quizTitle.textContent = quizInfo[0].infoType;
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 quizlength = quizWrap.querySelector(".seacrh__info span");
const quizCheck = quizWrap.querySelector(".quiz__check span");
let quizCount = 0;
let quizScore = 0;
선택자
- 선택자를 선택할 때 먼저 querSelector를 사용해서 선택자를 선택해 줍니다.
- Wrap을 선택 하고 필요한 선택자들을 가져와서 선택해 줍니다.
- 이 때 Type과 Time을 먼저 나타내 주기위해 전에 사용했던 document.querySelector(".quiz__title").innerHTML = quizInfo[0].infoType 이런식으로 출력해 줄 수 있었습니다. 하지만 이번에는 다른 방식이기에
- 먼저 변수 quizCount, quizScore 을 0으로 설정 합니다.
// 문제 출력
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 lengthTag = `
${quizInfo.length-index} 문제가 남았습니다.
`;
quizTitle.innerHTML = typeTag;
quizQuestion.innerHTML = questionTag;
quizChoice.innerHTML = choiceTag;
quizDesc.innerHTML = descTag;
quizlength.innerHTML = lengthTag;
문제출력
- updateQuiz 라는 자바스크립트 함수를 사용해서 index 매개변수를 받아 quizInfo 배열에서 해당 인덱스에 있는 퀴즈 정보를 바탕으로 HTML태그를 업데이트 하는 역할입니다.
- 함수 내부에서는 템플릿 리터럴을 사용해서 4개의 변수를 선언하고 각 변수는 HTML 태그를 생성하게 됩니다.
- typeTag 는 quizInfo 배열에서 저장된 인덱스의 infoType 속성과 infoTime 속성을 사용하여 span,em태그를 포함합니다.
- questionTag는 quizInfo 배열에서 저장된 인덱스의 infoQuestion 속성을 사용해서 em,span 태그를 포함합니다. em태그는 인덱스 값에 1을 더한 값으로 표시해서 저장된 번호가 아닌 인덱스 번호가 나와 문제의 번호가 1부터 나올 수 있게끔 설정해 줍니다.
- choiceTag는 quizInfo 배열에서 저장된 인덱스의 infoChoice 배열 요소 4개를 각각 대응하는 label,input,span태그로 만듭니다.
- descTag 현재 문제의 정답과 설명을 포함하는 HTML 태그를 생성합니다. infoAswer속성과 infoDesc속성을 사용합니다.
- lengthTag 는 현재 문제가 몇 문제 중 몇번째 문제인지 보여주는 HTML태그를 생성합니다.
- 불러올 때 innerHTML 프로퍼티를 사용하여 해당 요소들의 내부 HTML을 변경 해줍니다.
- 전체적으로 나타날때 `` 백틱 표시 안에 $ 를 넣어준 후 { } 안에 불러올 선택자 속성을 나타내 주면 됩니다.
// 객관식 선택
function choiceSelected(answer){
let userAnswer = answer.textContent; //사용자 정답
let currentAnswer = quizInfo[quizCount].infoAnswer; //문제 정답
if(userAnswer == currentAnswer){
console.log("정답입니다.");
dogWrap.classList.add("like");
quizScore++;
} else {
console.log("오답입니다.");
dogWrap.classList.add("dislike");
};
객관식 선택
- choiceSelected라는 함수를 정의 하고 answer라는 하나의 매개변수를 받게 됩니다.
- 먼저 answer는 매개변수의 텍스트 내용을 가져와서 사용자의 정답을 알아내고 quizInfo[quizCount].infoAnswer와 비교해서 문제 정답을 알아냅니다.
- 만약 userAnser와 currentAnswer가 같다면 정답입니다를 출력하고 dogWrap요소에 Like 웃고있는 강아지가 추가되면서 quizScore을 1 증가 시킵니다.
- 이 때 증가시키는 이유는 마지막 점수가 나올 때 맞힌 점수가 출력이 되기 위해 증가 시켜줍니다.
- 반면에 userAnswer와 currentAnswer가 다르다면 오답입니다를 출력하고 dogWrap요소에 disLike로 강아지가 시무룩한 표정이 추가됩니다.
// 보기 선택자
const quizChoiceSpan = quizWrap.querySelectorAll(".quiz__choice span");
const quizChoiceInput = quizWrap.querySelectorAll(".quiz__choice input");
// quizChoiceSpan.forEach((span, num) => {
// span.setAttribute("onclick", "choiceSelected(this)"); //원클릭할 때 ddd라는 함수를 실행시켜라
// });
for(let i=0; i<quizChoiceSpan.length; i++){
quizChoiceSpan[i].setAttribute("onclick", "choiceSelected(this)");
// quizChoiceInput[i].disabled = "true";
}
보기 선택자
- quizWrap 요소 내에서 quiz__choice 클래스를 가진 모든 input요소를 선택합니다.
- 그리고 quizChoiceSapn 배열의 각 요소에 대해 onclick 이벤트를 등록하고 choiceSelected(this)함수를 실행합니다.
- for문 반복문을 사용해서 quizChoicespan의 길이만큼 반복해서 각 요소에 onclick이벤트를 등록해서 choiceSelected(this)함수를 실행합니다.
- setAttribute() 메서드는 두개의 매개변수를 받고 설정된 속성을 제거 할 수 있습니다.
// 다음 버튼 숨기기, 해설 숨기기
quizAnswer.style.display = "none";
quizDesc.style.display = "none";
};
updateQuiz(quizCount);
// 다음 버튼, 해설 나타나기
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;
}
}
다음 버튼과 해설 / 갯수 나타내기
- quizAnswer과 quizDesc요소의 display 속성을 none으로 설정하는데 이를 통해 해당 요소가 화면에 표시 되지 않습니다.
- 그리고 updateQuiz(quizCount) 함수를 호출 합니다. quizCount 매개변수에 따라 다음 문제를 보여주는 역할을 합니다. 따라서 quizCount를 업데이트하고, 함수를 호출하여 다음 문제를 보여주게 됩니다.
- 그 후 버튼과 해설을 나타낼때는 block표시로 나타내 주는데 함수 밖에서 실행시켜 줍니다.
- 그리고 함수 밖에서 quizinfo.length 배열의 값 만큼 quizCount를 뺀 값이 1인 경우에 실행을 하게 되는데 마지막 문제를 푼 경우에 실행 시키는 조건문입니다. 문제의 정확도를 점수로 표시할 수 있습니다.
// 정답 확인
quizNext.addEventListener("click", () => {
quizCount++;
updateQuiz(quizCount);
dogWrap.classList.remove("like", "dislike");
});
</script>
정답 확인
quizNext 요소에 클릭 이벤트를 등록해서 이벤트가 발생하면 함수가 실행되는 코드입니다. quizCount변수를 증가시키고 updateQuiz()함수를 호출하여 다음 문제를 보여줍니다. 또한 dogWrap요소에서 Like와 disLike 클래스를 모두 제거합니다. 이전 문제에서 사용된 클래스를 초기화 하여 다음 문제에 영향을 주지 않도록 만들어 줍니다.