Winnie The Pooh Bear 자바스크립트 퀴즈 사이트 만들기 4

배움기록/JAVASCRIPT

자바스크립트 퀴즈 사이트 만들기 4

코딩은 처음이라 2023. 3. 18. 11:48

“ 지연되는 프로젝트에 인력을 더 투입하면 오히려 더 늦어진다. ”

- Frederick Philips Brooks
Mythical Man-Month 저자
728x90
반응형

자바스크립트 퀴즈 사이트 만들기 4

 

 

💜 퀴즈 4번째

코드 보기 / 완성 화면

 

오늘은 자바스크립트 퀴즈 만들기 4번째를 정리해 보겠습니다!

 

<body>
    <header id="header">
        <h1><a href="../javascript14.html">Quiz <em>객관식 확인하기(여러문제) 유형</em></h1></a>
        <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 class="active"><a href="quizEffect04.html">4</a></li>
            <li><a href="quizEffect05.html">5</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.hunmi961119@gmail.com">hunmi961119@gmail.com</a>
    </footer>
    <!-- //footer -->

body 안에 header, main, footer 로 구역을 나눠 작업해줍니다.

 

main 안에 퀴즈로 들어갈 각각의 이름들을 지정해 입력해줍니다.

 

객관식 문제들이기 때문에

quiz choice 태그를 만들어

안에 4개의 자식요소 태그를 또 만들어 줍니다.

 

<script>
    //선택자
    const quizWrap = document.querySelector(".quiz__wrap");
    const quizTitle = quizWrap.querySelector(".quiz__title");
    const quizQuestion = quizWrap.querySelector(".quiz__question");
    const quizChoice = quizWrap.querySelectorAll(".quiz__choice span");
    const quizSelect = quizWrap.querySelectorAll(".quiz__choice input");
    const quizAnswer = quizWrap.querySelector(".quiz__answer");
    const quizDesc = quizWrap.querySelector(".quiz__desc");
    const quizConfirm = quizWrap.querySelector(".quiz__answer .confirm");
    const dogWrap = quizWrap.querySelector(".dog__wrap");

그리고 아래에 script 안에서 퀴즈 문제를 작업해줍니다.

 

우선 선택자를 만들어줍니다

 

cosnt 변수를 이용해 각 태그에 맞는 이름들을 다 설정해줍니다.

 

다중이일 경우 querySelector 뒤에 All을 붙여줍니다.

 

    //문제 정보
    const quizInfo = [
        {
            infoType: "웹디자인 기능사",
            infoTime: "2016년 4회",
            infoNumber: "1",
            infoQuestion: "다음 중 디자인의 기본 요소들로 옳은 것은?",
            infoChoice: ["선, 색채, 공간, 수량", "점, 선, 면, 질감", "시간, 수량, 구조, 공간", "면, 구조, 공간, 수량"],
            infoAnswer: "2",
            infoDesc: "디자인의 기본 요소에는 점, 선, 면, 질감이 있습니다."
        }
    ]

그리고 아래에 

선택자 변수에 배열 안에 객체가 있는 형식으로

infoType, infoTime, infoNember 등 퀴즈만들기에 적합한 이름들로 만들어

문제 정보들을 저장해줍니다.

 

    //문제 출력
    //quizTitle.textContent = quizInfo[0].infoType + " " + quizInfo[0].infoTime;

    function updateQuiz(){
        quizTitle.innerHTML = quizInfo[0].infoType + " " + quizInfo[0].infoTime;
        quizQuestion.innerHTML = "<em>" + quizInfo[0].infoNumber + "</em>. " + quizInfo[0].infoQuestion;
        //quizAnswer.innerHTML = quizInfo[0].infoAnswer;
        quizDesc.innerHTML = quizInfo[0].infoDesc;

        for(let i=0; i<4; i++){
            quizChoice[i].textContent = quizInfo[0].infoChoice[i];
        }

        //해설 숨기기
        quizDesc.style.display = "none";

        //quizChoice.forEach(function(el, i){
        //    el.textContent = quizInfo[0].infoChoice[i];
        // });
    }

그 다음은 문제 출력을 만들어줍니다.

 

하나씩 입력해 출력할수도 있지만

복잡하기 때문에

함수를 이용해 출력해줍니다.

 

함수명을 updateQuiz로 입력해주고 작업합니다.

각 타이들에 맞게 들어갈 출력값들을 지정해 불러와줍니다.

 

함수 안에 for문을 사용해 

객관식 버튼 4개를 한번에 출력해줍니다.

 

그리고

quizdesc.style.display = "none";을 사용해 해설을 숨겨줍니다.

 

    function answerQuiz(){
        //사용자가 선택한 인풋박스(checked)  == 문제정답(quizInfo[0].infoAnswer)
        for(let i=0; i<quizChoice.length; i++){
            if(quizSelect[i].checked == true){//사용자가 보기를 체크한 상태 
                if(quizSelect[i].value == quizInfo[0].infoAnswer){
                    // alert("정답입니다.")
                    dogWrap.classList.add("like");
                } else {
                    // alert("오답입니다.")
                    dogWrap.classList.add("dislike");
                }
            }
        }

        //해설 보이기
        quizDesc.style.display = "block";

        //정답 숨기기
        quizAnswer.style.display = "none";
    };
    //정답 클릭
    quizConfirm.addEventListener("click", answerQuiz);
    //문제 출력
    updateQuiz();

마지막으로 함수 answerQuiz 안에

for문을 사용해 사용자가 입력한 답과

정답이 일치한지 확인하고 

정답인지 오답인지 알려주는 출력갑을 작성해줍니다.

 

💜 checked 

input요소에서 사용되는 속성 중 하나이다.

이 속성의 checkbox나 radio button 등의 input요소에서 해당 항복이 선택되었는지 여부를 나타내는 불리언 값이다.

 

 

다음은 CSS설정입니다.

강아지 css는 사이트를 참고해 가지고왔습니다.

https://wsss.tistory.com/913

 

좋아요! 싫어요!가 분명한 강아지 애니메이션

See the Pen Cute Dog by David López (@davidlpz) on CodePen. 좋아요! 싫어요!가 분명한 강아지 애니메이션

wsss.tistory.com

더보기
/* dog__wrap */
.dog .tail, 
.dog .chin, 
.dog .tongue::before, 
.dog .tongue::after, 
.dog .mouth, 
.dog .nose, 
.dog .teardrop, 
.dog .eyes, 
.dog .face::before, 
.dog .face::after, 
.dog .ears::before, 
.dog .ears::after, 
.dog__wrap {
    transition: 0.2s ease-in;
}
.dog__wrap {
    position: relative;
}
.dog__wrap .true {
    width: 120px;
    height: 120px;
    line-height: 120px;
    background-color: #87bb0e;
    border-radius: 50%;
    text-align: center;
    color: #fff;
    position: absolute;
    left: 70%;
    top: 100px;
    font-family: 'NanumBarunGothic';
    opacity: 0;
}
.dog__wrap .false {
    width: 120px;
    height: 120px;
    line-height: 120px;
    background-color: #87bb0e;
    border-radius: 50%;
    text-align: center;
    color: #fff;
    position: absolute;
    right: 70%;
    top: 100px;
    font-family: 'NanumBarunGothic';
    opacity: 0;
}
.dog__wrap.like .true {
    opacity: 1;
    animation: wobble 0.6s;

}
.dog__wrap.dislike .false {
    opacity: 1;
    animation: wobble 0.6s;
}
@keyframes wobble {
    0% {transform: translateX(0) rotate(0deg);}
    15% {transform: translateX(-25%) rotate(-5deg);}
    30% {transform: translateX(20%) rotate(3deg);}
    45% {transform: translateX(-15%) rotate(-3deg);}
    60% {transform: translateX(10%) rotate(2deg);}
    75% {transform: translateX(-5%) rotate(-1deg);}
    100% {transform: translateX(0) rotate(0deg);}
}
.card-container {
    position: relative;
    width: 360px;
    height: 378px;
    margin: auto;
    padding-top: 125px;
    border-radius: 3%;
    /* background: #fff; */
    z-index: 0;
}
.card-container::before,
.card-container::after {
    content: "";
    position: absolute;
    height: 100%;
    margin: auto;
    left: 0;
    right: 0;
    border-radius: 3%;
    z-index: -1;
}
.dog .head,
.dog .body {
    position: relative;
    width: 115px;
}
.dog .head {
    height: 115px;
    border-radius: 50% 50% 0 0;
    margin: 0 auto;
}
.dog .ears {
    position: relative;
    top: -14%;
    width: 100%;
}
.dog .ears::before,
.dog .ears::after {
    content: "";
    position: absolute;
    top: 0;
    width: 35px;
    height: 70px;
    background: #CB7A1D;
    border-top: 11px solid #F7AA2B;
    border-left: 7px solid #F7AA2B;
    border-right: 7px solid #F7AA2B;
}
.dog .ears::before {
    left: 0;
    border-radius: 50% 45% 0 0;
}
.dog .ears::after {
    right: 0;
    border-radius: 45% 50% 0 0;
}
.dog .face {
    position: absolute;
    background: #F7AA2B;
    width: 100%;
    height: 100%;
    border-radius: 50% 50% 0 0;
}
.dog .face::before,
.dog .face::after {
    content: "";
    display: block;
    margin: auto;
    background: #FEFEFE;
}
.dog .face::before {
    width: 15px;
    height: 35px;
    margin-top: 24px;
    border-radius: 20px 20px 0 0;
}
.dog .face::after {
    position: absolute;
    bottom: -1px;
    left: 0;
    right: 0;
    width: 60px;
    height: 65px;
    border-radius: 45% 45% 0 0;
}
.dog .eyes {
    position: relative;
    top: 29%;
    text-align: center;
}
.dog .eyes::before,
.dog .eyes::after {
    content: "";
    display: inline-block;
    width: 12px;
    height: 12px;
    border-radius: 100%;
    background: #451d1c;
    margin: 0 14.5%;
}
.dog .teardrop {
    position: absolute;
    top: 125%;
    left: 19%;
    width: 6px;
    height: 6px;
    border-radius: 0 50% 50% 50%;
    transform: rotate(45deg);
    background: #FEFEFE;
    visibility: hidden;
}
.dog .nose {
    position: relative;
    top: 35%;
    width: 16px;
    height: 8px;
    border-radius: 35px 35px 65px 65px;
    background: #451d1c;
    margin: auto;
}
.dog .mouth {
    position: relative;
    top: 34.5%;
    width: 4px;
    height: 6px;
    margin: 0 auto;
    text-align: center;
    background: #451d1c;
}
.dog .mouth::before,
.dog .mouth::after {
    content: "";
    position: absolute;
    top: -4px;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    border: 4px solid #451d1c;
    border-left-color: transparent;
    border-top-color: transparent;
    z-index: 2;
}
.dog .mouth::before {
    transform: translateX(-89%) rotate(45deg);
}
.dog .mouth::after {
    transform: translateX(-2px) rotate(45deg);
}
.dog .tongue {
    position: relative;
    z-index: 1;
}
.dog .tongue::before,
.dog .tongue::after {
    content: "";
    position: absolute;
}
.dog .tongue::before {
    top: 10px;
    left: -7px;
    width: 18px;
    height: 0;
    border-radius: 50%;
    background: #451d1c;
    z-index: -1;
}
.dog .tongue::after {
    top: 14px;
    left: -4px;
    width: 12px;
    height: 0;
    border-radius: 20px;
    background: #F5534F;
    z-index: 5;
}
.dog .chin {
    position: relative;
    top: 47.5%;
    margin: 0 auto;
    width: 12px;
    height: 12px;
    border-top: 10px solid #e8e7ec;
    border-left: 5px solid transparent;
    border-right: 5px solid transparent;
    border-radius: 2px;
    z-index: 0;
}
.dog .body {
    position: relative;
    height: 139px;
    margin: auto;
    z-index: 0;
}
.dog .body::before,
.dog .body::after {
    content: "";
    position: absolute;
    top: -1px;
    left: 0;
    right: 0;
    bottom: 0;
    display: block;
    width: 100%;
    margin: auto;
    background: #F7AA2B;
}
.dog .body::after {
    top: -2px;
    bottom: -1px;
    width: 60px;
    background: #FEFEFE;
}
.dog .tail {
    position: absolute;
    left: -60%;
    bottom: 1px;
    background: #F7AA2B;
    width: 93px;
    height: 15px;
    transform: rotate(45deg);
    transform-origin: 100% 50%;
    border-radius: 25px 0 0 25px;
    z-index: -2;
}
.dog .legs {
    position: absolute;
    bottom: 0;
    left: -10%;
    width: 120%;
    height: 15%;
    background: #F7AA2B;
    border-radius: 10px 10px 0 0;
}
.dog .legs::before,
.dog .legs::after {
    content: "";
    position: absolute;
    bottom: 1px;
    background: #CB7A1D;
    z-index: -1;
}
.dog .legs::before {
    left: -7.5%;
    width: 115%;
    height: 55%;
    border-radius: 5px 5px 0 0;
}
.dog .legs::after {
    left: -3.5%;
    width: 107%;
    height: 250%;
    border-radius: 20px 20px 35px 35px;
}
@keyframes movetongue {
    100% {
        height: 27px;
    }
}
@keyframes movetail {
    0% {
        transform: rotate(37deg);
    }
    100% {
        transform: rotate(52deg);
    }
}
@keyframes cry {
    100% {
        visibility: visible;
    }
}
.like {
    background: #ffffff;
}
.like .face::before {
    margin-top: 10px;
}
.like .face::after {
    height: 85px;
}
.like .eyes {
    top: 13%;
}
.like .eyes::before,
.like .eyes::after {
    width: 18px;
    height: 5px;
    margin: 0px 12.5%;
    transform: rotate(-37.5deg);
    border-radius: 20px;
}
.like .eyes::after {
    transform: rotate(37.5deg);
}
.like .nose {
    top: 18%;
}
.like .mouth {
    top: 16.5%;
}
.like .tongue::before {
    height: 12px;
}
.like .tongue::after {
    height: 24px;
    animation: movetongue 0.1s linear 0.35s infinite alternate forwards;
}
.like .chin {
    top: 34%;
}
.tail {
    animation: movetail 0.1s linear infinite alternate forwards;
}
.dislike {
    background: #363636;
}
.dislike .ears::before {
    transform: rotate(-50deg) translate(-7px, 2px);
}
.dislike .ears::after {
    transform: rotate(50deg) translate(7px, 2px);
}
.dislike .face::before {
    margin-top: 28px;
}
.dislike .face::after {
    height: 55px;
}
.dislike .eyes {
    top: 38%;
}
.dislike .eyes::before,
.dislike .eyes::after {
    width: 18px;
    height: 5px;
    margin: 0px 14.5%;
    transform: rotate(-37.5deg);
    border-radius: 20px;
}
.dislike .eyes::after {
    transform: rotate(37.5deg);
}
.dislike .teardrop {
    animation: cry 0.1s ease-in 0.25s forwards;
}
.dislike .nose {
    top: 44%;
}
.dislike .mouth {
    top: 42%;
}
.dislike .chin {
    top: 52%;
}
.dislike .tail {
    transform: rotate(0);
}

 

header, footer, quizwrap 

이름에 맞게 css설정을 해줍니다.

/* header */
#header {
    position: fixed;
    left: 0;
    top: 0;
    background-color: #262626;
    color: #fff;
    padding: 10px;
    width: 100%;
    z-index: 1000;
    display: flex;
    justify-content: space-between;
}
#header::before {
    content: '';
    border: 4px ridge #a3a3a3;
    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: #262626;
    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 #a3a3a3;
    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: #ffffff;
    border: 8px ridge #cacaca;
    margin: 10px;
}
.quiz__title {
    background-color: #cacaca;
    border: 3px ridge #cacaca;
    border-bottom-width: 6px;
    padding: 5px;
    font-family: 'DungGeunMo';
    font-size: 16px;
    color: #3b3b3b;
    text-align: center;
}
.quiz__question {
    padding: 20px;
    font-size: 24px;
    font-family: 'NanumBarunGothic';
    font-weight: bold;
    line-height: 1.5;
    border-bottom: 6px ridge #cacaca;
}
.quiz__question em {
    color: #ff3c3c;
}
.quiz__answer {
    font-family: 'NanumBarunGothic';
    padding: 20px;
    text-align: center;
    font-size: 24px;
    /* border-bottom: 6px ridge #cacaca; */
}
.quiz__answer .confirm {
    background-color: #f5ff9b;
    border: 6px ridge #cacaca;
    width: 100%;
    font-family: 'NanumBarunGothic';
    font-weight: bold;
    padding: 10px 20px;
    font-size: 22px;
    cursor: pointer;
    transition: all 0.3s;
}
.quiz__answer .confirm:hover {
    background-color: #f5ff9b;
}
.quiz__answer .result {
    background-color: #fff;
    border: 6px ridge #cacaca;
    width: 100%;
    font-family: 'NanumBarunGothic';
    padding: 10px 20px;
    font-size: 22px;
    /* display: none; */
}
.quiz__answer .input {
    background-color: #fff;
    border: 6px ridge #cacaca;
    width: 100%;
    font-family: 'NanumBarunGothic';
    padding: 10px 20px;
    font-size: 22px;
    margin-bottom: 10px;
}
.quiz__view {
    border-bottom: 6px ridge #cacaca;
    overflow: hidden;
}
.quiz__desc {
    border-top: 6px ridge #cacaca;
    padding: 20px;
    font-family: 'NanumBarunGothic';
    /* background-color: #e4e4e4; */
}
.quiz__desc::before {
    content: "✨Tip ";
    color: #F5534F;
    font-weight: bold;
}
.quiz__choice {
    padding: 20px;
    border-bottom: 6px ridge #cacaca;
    font-family: 'NanumBarunGothic';
}
.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 #d6e6b3;
    margin-right: 15px;
    transition: all 0.2s;
    flex-shrink: 0;
}
.quiz__choice label input:checked + span {
    background-color: #d7dac1;
    border-radius: 10px;
}
.quiz__choice label input:checked + span::before {
    box-shadow: inset 0 0 0 8px #6e9612;
}
.quiz__check {
    position: fixed;
    right: 20px;
    bottom: 20px;
    width: 130px;
    height: 130px;
    line-height: 130px;
    border-radius: 50% ;
    z-index: 1000;
    text-align: center;
    background-color: #6e9612;
    color: #fff;
    font-family: 'NanumBarunGothic';
    cursor: pointer;
}
.quiz__info {
    position: fixed;
    right: 20px;
    bottom: 170px;
    background-color: #6e9612;
    text-align: center;
    width: 130px;
    border-radius: 10px;
    height: 50px;
    line-height: 50px;
    font-family: 'NanumBarunGothic';
    color: #fff;
}
.quiz__info::after {
    content: '';
    position: absolute;
    left: 50%;
    margin-left: -10px;
    bottom: -10px;
    border-top: 10px solid #6e9612;
    border-left: 10px solid transparent;
    border-right: 10px solid transparent;
}

✨ width: calc(100% - 10px) 

calc() 함수를 이용해 요소의 너비를 계산하는 방법

 

✨ z-index 

속성 중 하나로, 요소의 쌓임 순서를 결정하는 값

반응형