본문 바로가기
JAVASCRIPT

객관식 여러문제 확인하기 유형 퀴즈 이펙트

by dongjin6539 2023. 3. 25.
728x90
반응형

객관식 여러문제 확인하기 유형 퀴즈 이펙트

수업 시간에 배운 내용을 복습하면서 해보겠습니다.

코드 보기(HTML, JAVASCRIPT / CSS1 / CSS2) / 완성화면

 

 

 

코드 블럭

<!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>퀴즈 이펙트05</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 class="active"><a href="quizEffect05.html">5</a></li>
            <li><a href="quizWebd.html">W</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="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="confirm">정답 확인하기</button>
                    </div>
                    <div class="quiz__desc"></div>
                </div>
            </div> -->
        </div>
    </main>     
    <!-- //main -->

    <footer id="footer">
        <a href="mailto:dongjin6539@naver.com">dongjin6539@naver.com</a>
    </footer>
    <!-- //footer -->
</body>
</html>

 

코드 블럭 구성

  • 코드 블럭 구성은 저번에 작성했던 객관식 확인하기 유형 퀴즈 이펙트에 있는 구성과 똑같아서 그대로 가져옵니다.(객관식 확인하기 유형 퀴즈 이펙트 : https://dongjin6539.tistory.com/43)
  • 다만 body 태그 안에 script 태그를 사용해서 정보를 입력하기 위해 main 태그에 class "quiz" 부분은 주석 처리 해줍니다.
  • 강아지 이미지는 인터넷을 통해 얻어왔습니다. (참조: https://wsss.tistory.com/913)
  • 위 페이지에 들어가서 코드펜을 통해 html 구조를 가져와서 main 구역에 입력해줍니다.(css 구조는 css 파일에 입력했습니다.)
  • CSS는 각 태그에 알맞는 속성을 입력하고 속성 값을 입력해줍니다.

 

CSS1

/* header */
#header {
    position: fixed;
    left: 0;
    top: 0;
    background-color: #000;
    color: #fff;
    padding: 10px;
    width: 100%;
    z-index: 1000;
    display: flex;
    justify-content: space-between;
}
#header::before {
    content: '';
    border: 4px ridge #cacaca;
    position: absolute;
    left: 5px;
    top: 5px;
    width: calc(100% - 10px);
    height: calc(100% - 10px);
}
#header h1 {
    font-size: 28px;
    padding: 5px 5px 5px 10px;
    font-family: 'DungGeunMo';
    z-index: 10;
    position: relative;
}
#header h1 a {
    color: #fff;
}
#header h1 em {
    font-size: 0.5em;
}
#header ul {
    padding: 5px;
}
#header li {
    display: inline;
    z-index: 10;
    position: relative;
}
#header li a {
    color: #fff;
    font-family: 'DungGeunMo';
    border: 1px dashed #fff;
    display: inline-block;
    padding: 5px;
}
#header li.active a,
#header li a:hover {
    background-color: #fff;
    color: #000;
}

/* footer */
#footer {
    position: fixed;
    left: 0;
    bottom: 0;
    width: 100%;
    background-color: #000;
    text-align: center;
}
#footer a {
    color: #fff;
    padding: 20px;
    display: block;
    font-family: 'DungGeunMo';
    z-index: 10;
    position: relative;
}
#footer::before {
    content: '';
    border: 4px ridge #cacaca;
    position: absolute;
    left: 5px;
    top: 5px;
    width: calc(100% - 10px);
    height: calc(100% - 10px);
}
#main {
    padding: 100px 0;
}

/* quiz__wrap */
.quiz__wrap {
    display: flex;
    justify-content: center;
    flex-wrap: wrap;
    align-items: flex-start;
}
.quiz__wrap .quiz {
    width: 500px;
    background-color: #fff;
    border: 8px ridge #000;
    margin: 10px;
}
.quiz__title {
    background-color: #000;
    border: 3px ridge #cacaca;
    border-bottom-width: 6px;
    padding: 5px;
    font-family: 'DungGeunMo';
    font-size: 16px;
    color: #fff;
    text-align: center;
}
.quiz__question {
    padding: 20px;
    font-size: 24px;
    font-family: 'PyeongChang';
    font-weight: 300;
    line-height: 1.4;
    border-bottom: 6px ridge #cacaca;
}
.quiz__question em {
    color: #cacaca;
}
.quiz__answer {
    font-family: 'PyeongChang';
    padding: 20px;
    text-align: center;
    font-size: 24px;
}
.quiz__answer .confirm {
    color: #fff;
    background-color: #000;
    border: 6px ridge #000;
    width: 100%;
    font-family: 'PyeongChang';
    padding: 10px 20px;
    font-size: 22px;
    cursor: pointer;
    transition: all 0.3s;
    font-weight: bold;
}
.quiz__answer .confirm:hover {
    color: #000;
    background-color: #cacaca;
}
.quiz__answer .result {
    background-color: #cacaca;
    border: 6px ridge #000;
    width: 100%;
    font-family: 'PyeongChang';
    padding: 10px 20px;
    font-size: 22px;
}
.quiz__answer .input {
    background-color: #fff;
    border: 6px groove #000;
    width: 100%;
    font-family: 'PyeongChang';
    padding: 10px 20px;
    font-size: 22px;
    margin-bottom: 10px;
}
.quiz__view {
    border-bottom: 6px ridge #cacaca;
    overflow: hidden;
}
.quiz__desc {
    border-top: 6px ridge #000;
    padding: 20px;
    font-family: 'PyeongChang';
    background-color: #cacaca;
}
.quiz__desc::before {
    content: '✍️ Tip ';
    color: #ff3c3c;
    font-weight: bold;
}
.quiz__choice {
    padding: 20px;
    border-bottom: 6px ridge #000;
    font-family: 'PyeongChang';
}
.quiz__choice label {
    display: flex;
}
.quiz__choice label input {
    position: absolute;
    clip: rect(0 0 0 0);
    width: 1px;
    height: 1px;
    margin: -1px;
    overflow: hidden;
}
.quiz__choice label span {
    font-size: 20px;
    line-height: 1.4;
    padding: 6px;
    display: flex;
    cursor: pointer;
    margin: 2px 0;
}
.quiz__choice label span::before {
    content: '';
    width: 26px;
    height: 26px;
    border-radius: 50%;
    background: #fff;
    box-shadow: inset 0 0 0 4px #000;
    margin-right: 15px;
    transition: all 0.2s;
    flex-shrink: 0;
}
.quiz__choice label input:checked + span {
    background-color: #cacaca;
    border-radius: 10px;
}
.quiz__choice label input:checked + span::before {
    box-shadow: inset 0 0 0 5px #cacaca;
    border: 4px solid #000;
}
.quiz__check {
    position: fixed;
    right: 10px;
    bottom: 60px;
    width: 150px;
    height: 150px;
    line-height: 150px;
    border-radius: 50%;
    z-index: 1000;
    text-align: center;
    background: #cacaca;
    color: #000;
    font-family: 'PyeongChang';
    cursor: pointer;
    border: 5px solid #000;
    font-size: 24px;
    padding-bottom: 100px;
}
.quiz__info {
    position: fixed;
    right: 20px;
    bottom: 220px;
    background-color: #cacaca;
    border: 5px solid #000;    
    text-align: center;
    width: 130px;
    height: 50px;
    line-height: 50px;
    border-radius: 10px;
    font-family: 'PyeongChang';
    color: #000;
    padding-bottom: 50px;
}
.quiz__info::after {
    content: '';
    position: absolute;
    left: 50%;
    margin-left: -10px;
    bottom: -10px;
    border-top: 10px solid #000;
    border-left: 10px solid transparent;
    border-right: 10px solid transparent;
}

 

CSS2

@import url('https://webfontworld.github.io/DungGeunMo/DungGeunMo.css');
@import url('https://webfontworld.github.io/PyeongChang/PyeongChang.css');

* {
    margin: 0;
    padding: 0;
}
*, *::before, *::after {
    box-sizing: border-box;
}
a {
    text-decoration: none;
    color: #222;
}
h1, h2, h3, h4, h5, h6 {
    font-weight: normal;
}
li, ul, ol {
    list-style: none;
}
img {
    vertical-align: top;
    width: 100%;
}
em {
    font-style: normal;
}
body {
    background:
        radial-gradient(#cacaca 3px, transparent 4px),
        radial-gradient(#cacaca 3px, transparent 4px),
        linear-gradient(#fff 4px, transparent 0),
        linear-gradient(45deg, transparent 74px, transparent 75px, #cacaca55 75px, #cacaca55 76px, transparent 77px, transparent 109px),
        linear-gradient(-45deg, transparent 75px, transparent 76px, #cacaca55 76px, #cacaca55 77px, transparent 78px, transparent 109px),
        #fff;
    background-size: 109px 109px, 109px 109px, 100% 6px, 109px 109px, 109px 109px;
    background-position: 54px 55px, 0px 0px, 0px 0px, 0px 0px, 0px 0px;
}

 

JAVASCRIPT

// 문제 정보
    const quizInfo = [
        {
            infoType: "문제 유형",
            infoTime: "문제 회차",
            infoNumber: "문제 1번",
            infoQuestion: "문제",
            infoChoice: {
                1: "보기 1",
                2: "보기 2",
                3: "보기 3",
                4: "보기 4"
            },
            infoAnswer: "정답",
            infoDesc: "문제 해설"
        },{
            infoType: "문제 정보",
            infoTime: "문제 회차",
            infoNumber: "문제 2번",
            infoQuestion: "문제",
            infoChoice: {
                1: "보기 1",
                2: "보기 2",
                3: "보기 3",
                4: "보기 4"
            },
            infoAnswer: "정답",
            infoDesc: "문제 해설"
        },....
    ];

    // 선택자
    const quizWrap = document.querySelector(".quiz__wrap");
    let quizScore = 0;

    // 문제 출력
    const updateQuiz = () => {
        const exam = [];

        quizInfo.forEach((question, number) => {
            exam.push(`
                <div class="quiz">
                    <div class="quiz__header">
                        <h2 class="quiz__title">${question.infoType} ${question.infoTime}</h2>
                    </div>
                    <div class="quiz__main">
                        <div class="quiz__question"><em>${number+1}</em>. ${question.infoQuestion}</div>
                        <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${number}">
                                <input type="radio" id="choice1${number}" name="choice${number}" value="1">
                                <span>${question.infoChoice[1]}</span>
                            </label>
                            <label for="choice2${number}">
                                <input type="radio" id="choice2${number}" name="choice${number}" value="2">
                                <span>${question.infoChoice[2]}</span>
                            </label>
                            <label for="choice3${number}">
                                <input type="radio" id="choice3${number}" name="choice${number}" value="3">
                                <span>${question.infoChoice[3]}</span>
                            </label>
                            <label for="choice4${number}">
                                <input type="radio" id="choice4${number}" name="choice${number}" value="4">
                                <span>${question.infoChoice[4]}</span>
                            </label>
                        </div>
                        <div class="quiz__desc"><em>정답은 ${question.infoAnswer}번 입니다.</em><br>${question.infoDesc}</div>
                    </div>
                </div>
            `);
        });

        exam.push(`
            <div class="quiz__info">??점</div>
            <div class="quiz__check">정답 확인</div>
        `);

        quizWrap.innerHTML = exam.join('');

        // 설명 숨기기
        document.querySelectorAll(".quiz__desc").forEach(el => el.style.display = "none");
    };
    updateQuiz();

    // 정답 확인
    const answerQuiz = () => {
        const quizChoices = document.querySelectorAll(".quiz__choice");

        // 사용자가 체크한 정답 == 문제 정답
        quizInfo.forEach((question, number) => {
            const userSelector = `input[name=choice${number}]:checked`;
            const quizSelectorWrap = quizChoices[number];
            const userAnswer = (quizSelectorWrap.querySelector(userSelector) || {}).value;
            const dogWrap = quizWrap.querySelectorAll(".dog__wrap");

            if(userAnswer == question.infoAnswer){
                console.log("정답")
                dogWrap[number].classList.add("like");
                quizScore++;
            } else {
                console.log("오답")
                dogWrap[number].classList.add("dislike");
            }
        });

        // 설명 보이기
        document.querySelectorAll(".quiz__desc").forEach(el => el.style.display = "block");

        // 점수 보이기
        document.querySelector(".quiz__info").innerHTML = Math.ceil((quizScore / quizInfo.length) * 100) + "점";
    };

    // 정답 클릭
    document.querySelector(".quiz__check").addEventListener("click", answerQuiz);
</script>

 

자바스크립트 구성

  • 변수의 이름을 저장해주는데 정해져 있는 것이 아니라 개개인 별로 차이가 있을 수 있습니다.
  • 문제의 정보를 "quizInfo"로 저장해서 배열 안에 객체가 형식으로 문제의 정보를 입력해줍니다.
  • 문제 유형은 "infoType", 문제 회차는 "infoTime",  문제 번호는 "infoNumber", 문제는 "infoQuestion", 문제 보기는 "infoChoice"로 입력하고 객체로 보기 번호를 입력해주고, 정답은 "infoAnswer", 문제 해설은 "infoDesc"로 입력해서 문제의 정보를 입력해줍니다.
  • 문제의 정보가 class "quiz__wrap"에 들어가야 되기 때문에 class 부분에 선택자를 만들어줍니다.
  • 문제를 출력하기 위해 변수를 updateQuiz로 저장하고 화살표 함수를 이용해서 문제를 출력해줍니다. 화살표 함수 안에 변수 exam으로 배열을 저장해줍니다. 배열 안에 문제의 정보를 입력하기 위해 문제의 정보 "quizInfo"를 객체가 다중이이므로 forEach( )를 사용해서 입력해줍니다. 
  • 배열 객체 메서드인 push를 사용해서 코드 블럭 구성에서 주석처리 해준 부분을 가져와서 exam.push로 배열 끝에 요소를 계속 추가시켜줍니다.
  • 가져온 부분에 문제 유형, 문제 회차, 문제 번호, 문제, 문제 보기, 정답. 문제 해설을 입력할 부분에 "quizInfo"의 값과 인덱스 값을 알맞는 부분에 입력을 시켜주고 forEach( ) 밖에 변수 updateQuiz( ); 를 출력시켜줍니다.
  • 출력시키고 웹페이지로 보게 되면 ,(콤마)가 있습니다. 그 부분을 없애주기 위해 배열 객체 매서드인 join를 사용해서 exam.join(' ')을 사용해서 요소를 추가시켜줍니다.
  • 추가로 exma.push를 사용해서 점수와 정답 확인하기 버튼을 만들어줍니다.
  • 문제를 풀기 전에 모든 문제의 해설을 모두 숨기기 위해  다중이 이므로 forEach( )를 사용해서 각 문제의 설명 값에 스타일을 display = "none"을 입력해줍니다.
  • 정답 확인하기 위해 변수 answrQuiz로 저장하고 화살표 함수를 이용해서 정답을 확인해줍니다.
  • 문제 보기의 보기를 선택자를 만들고 사용자가 체크한 정답과 문제의 정답이 같은지 확인하기 위해 quizInfo.forEach( ) 화살표 함수를 만들어줍니다. 
  • 화살표 함수 안에 각각 변수를 저장해주는데 사용자가 체크한 정답, 문제의 정답, 사용자가 체크한 정답이 맞고 틀리고의 값, 지난번에 사용했던 강아지를 변수를 저장해줍니다.
  • 사용자가 체크한 정답이 맞고 틀리고의 값과 quizInfo에 infoAnswer의 정답이 같은지 다른지를 if문을 사용해서 확인해줍니다.
  • 맞으면 정답과 해맑은 강아지, 틀리면 오답과 슬픈 강아지의 효과를 입력해줍니다. 
  • 정답 확인을 하면 설명을 보여주기 위해  forEach( )를 사용해서 각 문제의 설명 값에 스타일을 style.display = "none"을 입력했던 것을 style.display = "block"를 입력해줍니다.
  • 점수가 몇 점인지 확인하기 위해 변수 quizScore를 0으로 저장해줍니다. 
  • 정답을 확인하면 점수를 보여주기 위해 변수 answrQuiz로 저장하고 화살표 함수 부분에 정답이 맞으면 점수가 올라가게 하기 위해 if문 정답 부분에 quizScore++ 연산자를 입력해주document.querySelector(".quiz__info").innerHTML = Math.ceil((quizScore / quizInfo.length) * 100) + "점"; 입력해줍니다.
  • Math.ceil은 수학 메서드인 숫자를 올림을 해주는 메서드입니다.
  • 마지막으로 정답 확인하기 클릭하면 위의 스크립트가 적용되게끔 하기 위해 .addEventList("click") 메서드를 사용해줍니다.

 

참고

  • 아직 잘 모르는 자바스크립트 속성, 메서드에 대해 알아보겠습니다.
속성, 메서드 설명
push 배열 끝에 요소를 추가하고, 배열의 새로운 길이값을 반환합니다.
join 배열의 요소를 추가하여, 하나의 문자열로 반환합니다.
ceil 숫자 요소를 올림을 설정해줍니다.
addEventList("click") 이벤트 메서드로 클릭 했을 때 효과를 나타내줍니다.
 

https://dongjin6539.github.io/web2023/javascript/javascript14.html

 

728x90
반응형