본문 바로가기
JAVASCRIPT

퀴즈 이펙트 : 객관식 확인하기 : CBT 유형(json) 보충

by dongjin6539 2023. 4. 4.
728x90
반응형

퀴즈 이펙트 : 객관식 확인하기 : CBT 유형(json) 보충

https://dongjin6539.tistory.com/64 블로그 보충

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

 

 

코드 블럭 추가

<div class="cbt__start">
    <div class="cbt__modal1">
        <h2>기능사 시험</h2>
        <div class="cbt__choice">
            <select name="cbtTime" id="cbtTime">
                <option value="gineungsaJC2010_02">정보처리기능사 2010년 2회</option>
            </select>
            <select name="cbtTime" id="cbtTime">
                <option value="gineungsaWD2011_02">웹디자인기능사 2011년 2회</option>
            </select>
        </div>
        <button class="minimal">시작하기</button>
    </div>
</div>

 

구성

  • 모달 창을 만들어줍니다.
  • 모달 창에 문제 유형을 선택하는 것을 만들어줍니다.
  • 시험을 시작하는 버튼을 만들어줍니다.

 

CSS 추가

.cbt__start {
    position: fixed;
    left: 0;
    top: 0;
    width: 100%;
    height: 100vh;
    background-color: rgba(255, 255, 255, 0.4);
    z-index: 10000;
    backdrop-filter: blur(10px);
    display: flex;
    align-items: center;
    justify-content: center;
}
.cbt__start > div {
    width: 50%;
    height: 50vh;
    background-color: #fff;
    border: 8px ridge #cacaca;
    text-align: center;
}
.cbt__modal1 h2 {
    font-size: 30px;
    margin: 30px;
}
.cbt__modal1 select {
    border: 1px solid #cacaca;
    padding: 10px 30px;
    margin-bottom: 40px;
    font-family: 'PyeongChang';
}
.minimal {
    box-shadow: 2px 2px 5px rgba(0,0,0,0.15);
    background: #cacaca;
    display: grid;
    align-content: center;
    justify-content: center;
    border-radius: 5px;
    width: 300px;
    height: 80px;
    margin: 0 auto;
    font-family: 'PyeongChang';
    border: 1px solid #cacaca;
}
  • 각 태그에 맞게 적절한 스타일을 입력해줍니다.

JAVASCRIPT

<script>
    const cbtRest = document.querySelector(".cbt__rest");
    const cbtLength = document.querySelector(".cbt__length");
    
    let questionLength = 0;             // 전체 문제 수
    let questionRest = questionLength;  // 남은 문제 수 
    
    // 모달 창 없애기
    const cbtBtn = document.querySelector(".minimal");
    const cbtStart = document.querySelector(".cbt__start");

    cbtBtn.addEventListener("click", () => {
        cbtStart.style.display = "none";
    });
    
    // 타이머 만들기
    let minutes = 60;
    let seconds = 0;

    function countdown() {
        const timerElement = document.querySelector(".cbt__time");
        timerElement.innerHTML = `남은 시간 : ${minutes}분 ${seconds.toString().padStart(2, '0')}초`;

        if(seconds === 0){
            seconds = 59;
            minutes--;
        } else {
            seconds--;
        }
        if(minutes < 0){
            clearInterval(timer);
            alert("시험시간이 끝났습니다. 답안을 제출해주세요.");
        }
    }
    const timer = setInterval(countdown, 1000);
    
    // 문제 만들기
    const newQuestion = () => {
        const questionDesc = document.querySelectorAll(".cbt__question__desc");

        questionDesc.forEach(el => {
            if(el.innerHTML == "undefined"){
                el.style.display = "none";
            }
        });   
    };
    
    // 보기 체크
    const answerSelect2 = (elem) => {
        const answer = elem.value;      // 문제 보기의 값
        const answerNum = answer.split("_");

        const select = document.querySelectorAll(".cbt__omr .omr");   // 전체 문제 갯수(omr)
        const label = select[answerNum[0]].querySelectorAll("input");   // 보기 4개
        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");   // 전체 문제 갯수(문제)
        const label = select[answerNum[0]].querySelectorAll("input");   // 보기 4개
        label[answerNum[1]-1].checked = true;

        const answerInput = document.querySelectorAll(".cbt__selects input:checked");
        cbtRest.innerHTML = questionLength - answerInput.length;
    };
</script>

 

자바스크립트 구성

모달 창 없애기
  • 모달 창의 시작하기 버튼과 전체 구역을 선택자로 변수를 저장해줍니다.
  • 버튼을 클릭했을 때 전체 구역이 사라지도록 style.display="none";을 입력해줍니다.
타이머 만들기
  • 분과 초를 변수로 숫자 데이터를 저장해줍니다.
  • 함수를 이용해서 실행해주고 안에 시간이 있는 부분을 선택자로 만들어주고 선택자에 데이터를 입력하기 위해 .innerHTML을 써서 입력해줍니다.
  • if문을 사용해서 초가 0이 되면 초가 59로 바뀌게 하고 분이 --연산자를 이용해 감소하게 해줍니다. 초가 0이 아니면 초가 --연산자를 이용해 감소하게 해줍니다.
  • 또 if문을 사용해서 분이 0보다 작으면 타이머를 멈추게 해줍니다.  
  • 타이머 변수를 만들어 실행해줍니다. 1000을 쓴 이유는 스크립트에서 밀리초로 설정되어있어서 1000밀리초가 1초를 나타냅니다.
문제의 보기 설명 없애기
  • 각 문제별로 문제의 보기 설명이 없을 수가 있습니다.
  • 문제를 만들 때 보기가 나오거나 안나와야 하기 때문에 문제 만들기 함수에 입력을 해줍니다.
  • 문제의 보기 설명이 위치해 있는 곳을 선택자로 변수를 저장해줍니다.
  • 그 위치의 값이 undefined이면 사라지게 하기 위해 style.display="none";를 입력해서 없애줍니다.
보기 연동하기(문제의 보기, OMR 보기)
  • 전에 스크립트 코드에 문제의 보기 부분과 OMR 보기 부분에 onclick="answerSelect2(this)", onclick="answerSelect(this)" 각각 입력해줍니다.
  • 각각 함수를 만들어줍니다.
  • 변수 answer로 onclick의 값을 저장해줍니다.
  • 변수 answerNum으로 저장된 anwer의 값을 split("_")로 값을 저장해줍니다.
  • answerSelect2 부분에는 문제의 전체 문제 보기를 선택자로 만들고 answerSelect 부분에는 omr의 전체 문제 보기를 선택자로 만들어줍니다.
  • 전체 문제의 보기 input을 선택자로 만들어 체크가 된게 true로 만들어주면 서로 연동됩니다. 
문제를 풀었을 때 남은 문항 수 줄어들게 하기
  • 전체 문제와 남은 문제의 위치를 선택자 변수를 만들어줍니다.
  • 전체 문제 수와 남은 문제 수의 데이터를 저장해줍니다.
  • 문제를 풀었을 때 남은 문항 수가 줄어들게 하니까 보기 체크 함수 부분에 입력해줍니다. 문제의 보기와 omr 보기를 선택했을 때니까 두 군데 다 입력해줍니다.
  • 먼저 보기가 선택 됐을 때를 선택자로 만들어줍니다.
  • 선택자 남은 문항에 .innerHTML를 사용해서 데이터를 입력해줍니다. 
  • 남은 문항 수는 전체 문항 수에 보기가 선택 된 수를 빼주면 됩니다.

 

참고

  • 속성, 메서드
속성, 메서드 설명
toString( ) 문자열을 반환합니다.
padStart( ) 현재 문자열의 시작을 다른 문자열로 채워, 주어진 길이를 만족하는 새로운 문자열을 반환합니다. 채워넣기는 대상 문자열의 시작(좌측)부터 적용됩니다.
clearInterval 호출로 이전에 설정된 시간 제한 반복 작업을 취소합니다.
setInterval 호출 사이에 고정된 시간이 지연되면 이를 반복적으로 호출을 실행합니다.
split( ) 문자열 객체를 지정한 구분자를 이용하여 여러 개의 문자열로 나눕니다.

 

728x90
반응형