코딩 강의/컨텐츠를 만들어 볼까요

웹 언어 코딩으로 심리 테스트 만들기 #5 선다형, 단답형 복합 구현

아미넴 2021. 2. 26.
반응형

이번 시간은 기능을 대폭 강화해 보도록 할게요. 이전, 다음 버튼을 실제로 용도에 맞게 완성시키고 질문, 답변도 좀 더 다양하게 구성할 수 있도록 개선할 예정입니다.

 

웹 언어 코딩으로 심리 테스트 만들기 #4 데이터 입력

 

웹 언어 코딩으로 심리 테스트 만들기 #4 데이터 입력

기다리시는 분이 계셨을 지는 모르겠지만 ㅎㅎ 조금 늦어져서 죄송합니다. 이번에는 깊게 들어가면 복잡한 고급 스킬이지만 단순히 따라하기는 어렵지 않은 내용을 다루어 보겠습니다. 웹 언어

sangminem.tistory.com

 

목차

     

    HTML 구성 변경

    먼저 가장 기본이 되는 화면 구성부터 손 보겠습니다. test.html 파일에 변경된 부분이 좀 많습니다.

    <!DOCTYPE html>
    <html>
        <head>
            <meta name="viewport" content="initial-scale=1.0, width=device-width">
            <link rel="stylesheet" href="./css/test.css">
            <title>샘플 심리 테스트</title>
            <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
            <script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
        </head>
        <body>
            <div id="test">
                <div id="intro" class="intro-wrap">
                    <!-- 도입부 -->
                    <div class="intro">
                        <div class="intro-story" v-on:click="start">{{intro}}</div>
                    </div>
                </div>
                <div id="main">
                    <!-- 타이틀 -->
                    <div class="title-wrap">
                        <h2 class="title">{{title}}</h2>
                    </div>
    
                    <!-- 질문 -->
                    <div class="question-wrap">
                        <h3 class="question">
                            {{qna[currentIndex].q}} <!-- question[index] -> qna[currentIndex].q 로 변경 -->
                        </h3>
                    </div>
                    
                    <!-- 답변 -->
                    <div class="answer-wrap">
                        <!-- 선다형, 단답형 구현을 위해 변경 시작 -->
                        <div v-for="(qVal, qIdx) in qna" :id="'q'+qIdx">
                            <div v-if="qna[qIdx].a != null">
                                <div v-if="qIdx == currentIndex" v-for="(aVal, aIdx) in qna[qIdx].a" class="answer">
                                    <input type="radio" :name="'q'+qIdx" :id="'q'+qIdx+'a'+aIdx" :value="qna[qIdx].a[aIdx]" v-model="qna[qIdx].r">
                                    <label :for="'q'+qIdx+'a'+aIdx">{{aVal}}</label>
                                </div>
                            </div>
                            <div v-if="qna[qIdx].a == null">
                                <input v-if="qIdx == currentIndex" class="answer-text" type="text" :id="'q'+qIdx+'a0'" v-model="qna[qIdx].r" placeholder="">
                            </div>
                        </div>
                        <!-- 선다형, 단답현 구현을 위해 변경 끝 -->
                    </div>
                    
                    <!-- 하단 버튼 -->
                    <div class="bottom">
                        <div class="controller-wrap">
                            <button class='prev-btn' v-on:click="prev">이전</button>
                            <button class='next-btn' v-on:click="next">다음</button>
                        </div>
                    </div>
                </div>
                
                <!-- 결과 -->
                <div id="result" class="result-wrap">
                    <div class="result">{{result}}</div>
                </div>
            </div>
            <script src="./js/test.js"></script>
        </body>
    </html>

    처음에 따로 question 배열로 선언하여 관리했던 질문 변수를 질문과 답을 하나로 묶어 관리하는 것이 낫겠다고 판단하여 qna라는 배열을 선언해서 그 안에 q라는 필드에 배열 형태로 삽입했습니다. 데이터 구조는 JSON 오브젝트 형태인데 복잡하지는 않으니 잘 모르셔도 일단 따라 작성하시기 바랍니다. 그리고 질문 index 변수명을 currentIndex로 변경하였습니다.

     

    다음에 나오는 선다형, 단답형을 구성하는 부분이 모든 부분 통틀어서 가장 복잡합니다. v-if 부터 v-for, v-model 등 당장 설명하기 어려운 개념들이 많이 등장합니다. 모든 것을 상세히 설명하려면 따로 시간을 내야할 정도로 분량이 많으므로 간단히만 설명하고 넘어가려고 합니다. 좀 더 공부하고 싶은 분들을 위해 참고할 수 있는 아래 링크를 남겨 놓겠습니다.

     

    v-if는 선다형과 단답형 유형을 구분하고 인덱스에 따른 현재 문항을 가져오기 위해 사용하였고, v-for는 선다형의 문항 개수가 여러 개이므로 반복적으로 구성하기 위해 사용하였습니다. v-model은 radio 버튼으로 선택한 값을 저장하기 위한 변수를 대입하는 속성입니다.

     

    v-if - 조건부 렌더링

     

    조건부 렌더링 — Vue.js

    Vue.js - 프로그레시브 자바스크립트 프레임워크

    kr.vuejs.org

    v-for - 리스트 렌더링

     

    리스트 렌더링 — Vue.js

    Vue.js - 프로그레시브 자바스크립트 프레임워크

    kr.vuejs.org

    v-model - 폼 입력 바인딩

     

    폼 입력 바인딩 — Vue.js

    Vue.js - 프로그레시브 자바스크립트 프레임워크

    kr.vuejs.org

     

    질문 답 데이터 입력

    다음으로 test.js 파일에 질문 답 데이터를 입력해 보도록 하겠습니다. 개념을 완벽히 숙지하지 않아도 차근차근 따라가시면 어렵지 않습니다.

    var test = new Vue({
        el: '#test',
        data: {
            intro: '테스트를 시작 합니다',
            title: '샘플 테스트',
            currentIndex: 0, // index 에서 이름 변경
            qna: [], // 새로 선언, question[], answer[], selection[] 제거
            result: ''
        },
        beforeMount: function() {
            // 질문, 답 데이터 입력
            this.insertQna('Q1. 숲 속을 걷고 있는 당신 앞에 불쑥 나타난 동물! 어떤 동물일까?', null, 'text');
            this.insertQna('Q2. 당신의 눈 앞에 보이는 벌레는 몇 마리일까?', [1,2,3,4,5], null);
        },
        mounted: function() {
            // 생략
        },
        methods: {
            // 질문, 답을 입력하기 위한 함수 구현
            insertQna: function(q, a, t) {
                // 질문, 답, 선택, 타입(문자, 숫자 등)으로 구성된 JSON 형태의 데이터 오브젝트
                var item = {
                    q: q,
                    a: a,
                    r: '',
                    t: t
                };
                // qna 배열에 삽입
                this.qna.push(item);
            }
        },
        // 생략
    });

    질문 답을 입력 받기 위해 insertQna라는 메서드를 구현하였습니다. q에는 질문이 들어가고 a에는 답지가 들어가는데 단답형은 답지가 비어 있어야 하므로 null을 넣고 숫자, 문자를 구분하기 위해 t에 타입(text, number 등)을 넣어 주도록 하였습니다. 그리고 선다형일 경우에는 a에 선택 문항을 배열 형태로 넣어주었습니다. 직접 값을 입력하는 것이 아니라 선택하는 것이므로 t에 타입을 지정하지 않고 null을 넣어 주었습니다. 데이터는 화면이 구성되기 전에 미리 입력되어 있어야 하므로 beforeMount 영역에 작성해 주었습니다. vueJS에서 제공하는 기능 중 하나이므로 알고만 넘어가시면 됩니다.

     

     

    이전, 다음 버튼 구현

    이번에는 지난 시간까지 적당히 넘겼던 이전, 다음 버튼을 제대로 구현해 보겠습니다.

    var test = new Vue({
        el: '#test',
        data: {
            // 생략
        },
        beforeMount: function() {
            // 생략
        },
        mounted: function() {
            // 생략
        },
        methods: {
            // 생략
            start: function() {
                $('#intro').hide();
                $('#main').show();
                $('#result').hide();
    
                var self = this;
                setTimeout(function() {
                    if(typeof self.qna[0].t != 'undefined' && self.qna[0].t != null) {
                        $('#q0a0').attr('type', self.qna[0].t);
                        $('#q0a0').focus();
                    }
                }, 200);
            },
            next: function () {
                var self = this;
                if(this.currentIndex < this.qna.length-1) {
                    this.currentIndex++;
                    if(typeof this.qna[this.currentIndex].t != 'undefined' && this.qna[this.currentIndex].t != null) {
                        setTimeout(function() {
                            $('#q'+self.currentIndex+'a0').attr('type', self.qna[self.currentIndex].t);
                            $('#q'+self.currentIndex+'a0').focus();
                        }, 200);                    
                    }
                } else {
                    var check = true;
                    for(var i=0; i < this.qna.length; i++) {
                        if(this.qna[i].r === '') {
                            check = false;
                        }
                    }
                    if(check) {
                        this.showResult();
                    } else {
                        alert("아직 완료되지 않았습니다.");
                    }
                }
            },
            prev: function () {
                var self = this;
                if(this.currentIndex > 0) {
                    this.currentIndex--;
                    if(typeof this.qna[this.currentIndex].t != 'undefined' && this.qna[this.currentIndex].t != null) {
                        setTimeout(function() {
                            $('#q'+self.currentIndex+'a0').attr('type', self.qna[self.currentIndex].t);
                            $('#q'+self.currentIndex+'a0').focus();
                        }, 200);                    
                    }
                } else {
                    alert('첫 질문입니다.');
                }
            }
        }
    });

    다음 버튼을 누를 경우(next 메서드) 전체 질문 수보다 currentIndex 값이 적으면 다음 질문으로 이동하도록 하였고 그 때 선다형인 지 단답형인 지를 판단하여 단답형일 경우 커서 포커스를 입력 박스에 두도록 하였습니다. 더 이상 다음 질문이 없을 경우에는 먼저 모든 답이 입력되었는 지 판단하여 전부 입력되었으면 결과 화면으로 이동하게 하였고 완료되지 않은 문항이 있으면 알림 창을 띄워 주도록 하였습니다.

     

    이전 버튼도 마찬가지로(prev 메서드) 첫 번째 질문이 아닐 경우만 제외하고 제한 없이 이동할 수 있도록 하였고 마찬가지로 단답형일 경우 입력 박스에 포커스를 가져 가도록 했습니다. 이전 버튼 누른 위치가 첫 번째 질문이라면 알림 창을 띄워 주었습니다.

     

    참고로 최초 메인 화면 진입 시(start 메서드) 첫 번째 질문에서도 단답형일 경우 입력 박스 포커스를 두도록 하였습니다.

     

    결과 화면 구성

    마지막으로 답변을 토대로 결과 화면을 구성해 보겠습니다. 이번 시간에는 기능만 간단하게 구현할 생각입니다.

    var test = new Vue({
        el: '#test',
        data: {
            // 생략
        },
        beforeMount: function() {
            // 생략
        },
        mounted: function() {
            // 생략
        },
        methods: {
            // 생략
            showResult: function() {
                this.result =  'Q1. 불쑥 나타난 동물 = '+this.qna[0].r+'\n=> 사람들이 나를 보는 모습\n\n';
                this.result += 'Q2. 눈 앞의 벌레 수 = '+this.qna[1].r+'마리\n=> 나를 화나게 하는 사람 수\n\n';
                $('#main').hide();
                $('#result').show();
            }
        }
    });

    답변과 함께 그 의미를 간단하게 텍스트로 구성하여 result 변수에 담아 보았습니다. 그리고 jQuery를 이용하여 메인 블럭은 숨기고 결과 블럭을 나타나게 하였습니다. 결과 블럭에 구성한 result 변수 내용이 보여지게 됩니다.

     

    CSS 꾸미기

    input 박스를 있는 그대로 사용하면 예쁘지 않아서 새롭게 꾸며보겠습니다.

    input {
        color: rgb(40, 92, 24);
    }
    input:focus {
        color: rgb(40, 92, 24);
    }
    input[type=text],
    input[type=number] {
        background: none;
        border: 0;
        border-bottom: solid 3px rgb(40, 92, 24);
    }
    input::placeholder {
        color:  rgb(40, 92, 24);
        opacity: 0.5;
    }
    input:focus,
    select:focus,
    textarea:focus,
    button:focus {
        outline: none;
    }

    input 태그의 기본 속성을 대부분 제거하고 새롭게 작성하였습니다. 꾸미는 부분은 따로 자세히 설명하지는 않겠습니다. 일단 그대로 작성하시고 본인만의 스타일을 적용하고 싶으신 분은 CSS 문법 공부를 조금만 공부해서 변경해 보세요. 여기저기 쓸모가 많아서 한 번 알아 두시면 손해는 아닐 겁니다.

     

    다음은 새롭게 추가한 단답형 관련 클래스 입니다.

    .answer-text {
        margin-left: 20px;
        padding-bottom: 5px;
    }

    여백, 간격 등만 조절한 코드이므로 특별히 설명할 부분은 없습니다.

     

     

    전체 소스 제공

    설명이 다소 복잡하고 이곳 저곳 많이 고쳐서 헷갈릴 소지가 있으므로 중간 점검 차원에서 현재까지 개발한 소스를 공유하겠습니다.

    test.html 소스 내용

    입력 후 파일 이름을 test.html로 저장해 주시면 됩니다.

    <!DOCTYPE html>
    <html>
        <head>
            <meta name="viewport" content="initial-scale=1.0, width=device-width">
            <link rel="stylesheet" href="./css/test.css">
            <title>샘플 심리 테스트</title>
            <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
            <script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
        </head>
        <body>
            <div id="test">
                <!-- 도입부 -->
                <div id="intro" class="intro-wrap">
                    <div class="intro">
                        <div class="intro-story" v-on:click="start">{{intro}}</div>
                    </div>
                </div>
                <div id="main">
                    <!-- 타이틀 -->
                    <div class="title-wrap">
                        <h2 class="title">{{title}}</h2>
                    </div>
                    <!-- 질문 -->
                    <div class="question-wrap">
                        <h3 class="question">
                            {{qna[currentIndex].q}}
                        </h3>
                    </div>
                    <!-- 답변 -->
                    <div class="answer-wrap">
                        <div v-for="(qVal, qIdx) in qna" :id="'q'+qIdx">
                            <div v-if="qna[qIdx].a != null">
                                <div v-if="qIdx == currentIndex" v-for="(aVal, aIdx) in qna[qIdx].a" class="answer">
                                    <input type="radio" :name="'q'+qIdx" :id="'q'+qIdx+'a'+aIdx" :value="qna[qIdx].a[aIdx]" v-model="qna[qIdx].r">
                                    <label :for="'q'+qIdx+'a'+aIdx">{{aVal}}</label>
                                </div>
                            </div>
                            <div v-if="qna[qIdx].a == null">
                                <input v-if="qIdx == currentIndex" class="answer-text" type="text" :id="'q'+qIdx+'a0'" v-model="qna[qIdx].r" placeholder="">
                            </div>
                        </div>
                    </div>
                    <!-- 하단 버튼 -->
                    <div class="bottom">
                        <div class="controller-wrap">
                            <button class='prev-btn' v-on:click="prev">이전</button>
                            <button class='next-btn' v-on:click="next">다음</button>
                        </div>
                    </div>
                </div>
                <!-- 결과 -->
                <div id="result" class="result-wrap">
                    <div class="result">{{result}}</div>
                </div>
            </div>
            <script src="./js/test.js"></script>
        </body>
    </html>

     

    test.js 소스 내용

    test.html 파일 저장한 위치에서 js 폴더 하나 만들어서 넣어 주세요.

    var test = new Vue({
        el: '#test',
        data: {
            intro: '테스트를 시작 합니다',
            title: '샘플 테스트',
            currentIndex: 0,
            qna: [],
            result: ''
        },
        beforeMount: function() {
            this.insertQna('Q1. 숲 속을 걷고 있는 당신 앞에 불쑥 나타난 동물! 어떤 동물일까?', null, 'text');
            this.insertQna('Q2. 당신의 눈 앞에 보이는 벌레는 몇 마리일까?', [1,2,3,4,5], null);
        },
        mounted: function() {
            $('#intro').show();
            $('#main').hide();
            $('#result').hide();
        },
        methods: {
            insertQna: function(q, a, t) {
                var item = {
                    q: q,
                    a: a,
                    r: '',
                    t: t
                };
                this.qna.push(item);
            },
            start: function() {
                $('#intro').hide();
                $('#main').show();
                $('#result').hide();
    
                var self = this;
                setTimeout(function() {
                    if(typeof self.qna[0].t != 'undefined' && self.qna[0].t != null) {
                        $('#q0a0').attr('type', self.qna[0].t);
                        $('#q0a0').focus();
                    }
                }, 200);
            },
            next: function () {
                var self = this;
                if(this.currentIndex < this.qna.length-1) {
                    this.currentIndex++;
                    if(typeof this.qna[this.currentIndex].t != 'undefined' && this.qna[this.currentIndex].t != null) {
                        setTimeout(function() {
                            $('#q'+self.currentIndex+'a0').attr('type', self.qna[self.currentIndex].t);
                            $('#q'+self.currentIndex+'a0').focus();
                        }, 200);                    
                    }
                } else {
                    var check = true;
                    for(var i=0; i < this.qna.length; i++) {
                        if(this.qna[i].r === '') {
                            check = false;
                        }
                    }
                    if(check) {
                        this.showResult();
                    } else {
                        alert("아직 완료되지 않았습니다.");
                    }
                }
            },
            prev: function () {
                var self = this;
                if(this.currentIndex > 0) {
                    this.currentIndex--;
                    if(typeof this.qna[this.currentIndex].t != 'undefined' && this.qna[this.currentIndex].t != null) {
                        setTimeout(function() {
                            $('#q'+self.currentIndex+'a0').attr('type', self.qna[self.currentIndex].t);
                            $('#q'+self.currentIndex+'a0').focus();
                        }, 200);                    
                    }
                } else {
                    alert('첫 질문입니다.');
                }
            },
            showResult: function() {
                this.result =  'Q1. 불쑥 나타난 동물 = '+this.qna[0].r+'\n=> 사람들이 나를 보는 모습\n\n';
                this.result += 'Q2. 눈 앞의 벌레 수 = '+this.qna[1].r+'마리\n=> 나를 화나게 하는 사람 수\n\n';
                $('#main').hide();
                $('#result').show();
            }
        }
    });

     

    test.css 소스 내용

    test.html 파일 저장한 위치에서 css 폴더 하나 만들어서 넣어 주세요.

    html, button {
        font-size: 16px;
    }
    button {
        margin: 0;
        padding: 0;
        border: 0;
        background: none;
    }
    input {
        color: rgb(40, 92, 24);
    }
    input:focus {
        color: rgb(40, 92, 24);
    }
    input[type=text],
    input[type=number] {
        background: none;
        border: 0;
        border-bottom: solid 3px rgb(40, 92, 24);
    }
    input::placeholder {
        color:  rgb(40, 92, 24);
        opacity: 0.5;
    }
    input:focus,
    select:focus,
    textarea:focus,
    button:focus {
        outline: none;
    }
    body {
        margin: 0;
        overflow: hidden;
    }
    #main::after {
        content: "";
        position: absolute;
        left: 0;
        top: 0;
        width: 100%;
        height:100%;
        background:red;
        opacity: 0.1;
        z-index: -1;
    }
    
    .title-wrap {
        display: table;
        position: relative;
        width:100vw;
        height:80px;
    }
    
    .title {
        display: table-cell;
        text-align: center;
        vertical-align: middle;
    }
    
    .question-wrap {
        display: table;
        position: relative;
        width:100vw;
        height:100px;
    }
    
    .question {
        display:table-cell;
        vertical-align:middle;
        padding-left: 20px;
    }
    
    .answer-wrap {
        position: relative;
        width:100vw;
        cursor: pointer;
    }
    
    .answer {
        padding: 10px;
        font-weight: bold;
    }
    
    .answer-text {
        margin-left: 20px;
        padding-bottom: 5px;
    }
    
    .bottom {
        position: fixed;
        bottom: 0;
        width: 100%;
    }
    
    .controller-wrap {
        display: table;
        position: relative;
        width:100vw;
        height:70px;
    }
    
    .prev-btn {
        width:50%;
        height: 100%;
        display: table-cell;
        vertical-align:middle;
        text-align:center;
        font-size: 1.2em;
        font-weight: bold;
        cursor: pointer;
    }
    .prev-btn::after {
        content: "";
        position: absolute;
        left: 0;
        top: 0;
        width: 50%;
        height:100%;
        background:yellow;
        opacity: 0.1;
        z-index: -1;
    }
    .next-btn {
        width:50%;
        height: 100%;
        display: table-cell;
        vertical-align:middle;
        text-align:center;
        font-size: 1.2em;
        font-weight: bold;
        cursor: pointer;
    }
    .next-btn::after {
        content: "";
        position: absolute;
        right: 0;
        top: 0;
        width: 50%;
        height:100%;
        background:blue;
        opacity: 0.1;
        z-index: -1;
    }
    
    .intro-wrap {
        display: table;
        position: relative;
        width:100vw;
        height:100vh;
    }
    .intro-wrap::after {
        content: "";
        position: absolute;
        left: 0;
        top: 0;
        width: 100%;
        height:100%;
        background:orange;
        opacity: 0.2;
        z-index: -1;
    }
    .intro {
        display: table-cell;
        text-align: center;
        vertical-align: middle;
    }
    .intro-story {
        font-size: 1.5em;
        font-weight: bold;
        white-space: pre;
    }
    
    .result-wrap {
        display: table;
        position: relative;
        width:100vw;
        height:100vh;
    }
    .result-wrap::after {
        content: "";
        position: absolute;
        left: 0;
        top: 0;
        width: 100%;
        height:100%;
        background:blue;
        opacity: 0.1;
        z-index: -1;
    }
    .result {
        display: table-cell;
        text-align: center;
        vertical-align: middle;
        white-space: pre;
        font-size: 1.2em;
        font-weight: bold;
    }

     

     

    결과 확인

    인트로 부분입니다

    중앙 텍스트를 클릭하면 메인 화면으로 넘어 갑니다.

     

    메인 화면 첫 번째 질문입니다.

     

    이전 버튼을 누르면 다음과 같은 알림 창이 뜹니다.

     

    다음 버튼을 누르니 두 번째 질문이 잘 보이네요. 선다형이 잘 표현 되었습니다.

     

    답을 선택하지 않고 다음 버튼을 누르니 알림 창도 잘 뜹니다.

     

    모든 답을 입력하고 다음 버튼을 눌러 보면 결과까지 잘 표현이 되는 것을 알 수 있습니다.

     

    지금까지 선다형, 단답형 구조까지 필요한 모든 기능이 구현 되었습니다. 앞으로는 이 기능을 활용하여 좀 더 많은 문항을 표현하고 답변을 토대로 결과를 만들어 내는 부분만 변경을 하면 다양한 컨텐츠를 만들어 낼 수 있을 것 같습니다.

     

    다음 시간에는 테스트 시작 전과 결과 표시 전에 필요한 멘트를 좀 더 넣어 보겠습니다. 그리고 페이지 이동 시 애니메이션 효과도 구현하도록 하겠습니다.

     

    감사합니다 :)

    반응형
    그리드형(광고전용)

    댓글21

    • 익명 2021.03.02 11:41

      비밀댓글입니다
      답글

    • 익명 2021.03.02 11:45

      비밀댓글입니다
      답글

      • 아미넴 2021.03.02 14:59 신고

        안녕하세요.
        첫 강의부터 차근차근 따라오셨다면 눈치 채셨을 텐데, css는 css 폴더에 js는 js폴더에 넣어 주셔야 정상 동작합니다 ㅎㅎ
        더 궁금하신 점 있으시면 말씀해 주세요~

    • 익명 2021.03.15 17:06

      비밀댓글입니다
      답글

    • 익명 2021.03.21 22:56

      비밀댓글입니다
      답글

      • 아미넴 2021.03.21 23:54 신고

        안녕하세요. 학생이시군요 ㅎㅎ

        쉽게 생각해서 Visuail Studio Code는 단순히 텍스트 에디터에 불과합니다. 메모장에 작성해도 똑같은 결과를 낼 수 있다는 얘기죠. 다만 메모장 보다는 다양한 기능이 있어서 좀 더 쉽게 코드를 작성할 수 있게 해준다는 정도의 차이만 있습니다. 물론 좀 더 깊게 들어가면 그 외에 다양한 기능들이 더 있지만 지금은 이 정도로만 이해하시는 편이 좋겠습니다.

        그보다 중요한 것은 HTML, 자바스크립트, CSS를 얼마나 이해하느냐인데 당연히 바로 알 수는 없고 기초 공부를 먼저 하고 시작하시는 걸 추천드립니다.

    • J 2021.03.22 01:33

      아까 학생입니다. 폴더의 개념을 알려주실수있나요?
      그리고 조건부 렌더링 v for v if 등을 어떻게 써야하는지도요 ㅠ
      답글

      • 아미넴 2021.03.22 11:13 신고

        폴더는 우리가 파일탐색기에서 만드는 그 새폴더 생성 얘기라서 더 설명할 것이 없구요 ㅎㅎ
        vueJS는 댓글로 간단히 설명이 어려워서 링크 남겨 놓았으니 따로 공부 하셔야 합니다. 그냥 적당히 따라 작성하는 수준이라면 모를까 단기간에 의미를 하나하나 이해하며 진행하기는 힘듭니다.
        혹시 공부하다가 모르는 부분은 질문하시면 도와드릴 수 있을 것 같아요.

    • J 2021.03.22 17:08

      폴더를 만드는게 비쥬얼 스튜디오 안에서 만드는 폴더죠?
      답글

    • 익명 2021.04.05 15:42

      비밀댓글입니다
      답글

    • 12347 2021.04.05 15:43

      질문 하나해도 될까요??
      질문 문항이 50개일때
      beforeMount: function() {
      // 질문, 답 데이터 입력
      this.insertQna('Q1. 숲 속을 걷고 있는 당신 앞에 불쑥 나타난 동물! 어떤 동물일까?', null, 'text');
      this.insertQna('Q2. 당신의 눈 앞에 보이는 벌레는 몇 마리일까?', [1,2,3,4,5], null);
      },
      여기 안하에 50개를 다 넣으면 되나요??

      답글

      • 아미넴 2021.04.05 16:02 신고

        네 안녕하세요. 50개를 다 넣으면 50개를 조합하여 결과를 산출하는 로직도 작성해야 하는데 그건 또 다른 문제라서.. 단순하게 말할 수 있는 부분은 아닐거 같습니다 ㅎㅎ 질문 입력은 말씀하신 대로 해도 되지만 50개의 결과를 입력받고 데이터를 저장하여 의미 있는 결과를 도출하려면 그에 맞게 로직을 작성해야 하는 등 추가로 해줘야 하는 작업이 많거든요.

        간단하게 5개 이하의 질문의 답을 받아 결과를 보여주는건 어렵지 않기 때문에 그 수준으로 일단 해보시고 좀 더 심화적으로 접근하는 것이 좋아 보입니다.

    • 김지연222 2021.10.20 20:15 신고

      글 잘 봤습니다! 혹시 괜찮으시면 깃허브 알 수 있을까요?

      답글

    • 김지연222 2021.11.15 16:44 신고

      포스팅덕분에 어렵지 않게 잘 구현할 수 있었습니다! 감사합니다!!! 혹시 질문들을 다섯개정도 만들어서 각대답의 결과를 맨마지막에 5개 각각 도출해내는 방식 말고 다섯개의 질문의 대답들에 의해 한가지의 결과를 도출해내려고 하면 if문을 활용해봐야하는건가요?
      답글

      • 아미넴 2021.11.15 23:11 신고

        제가 예시로 각 질문에 대한 대답을 그냥 쭉 찍어내는 것만 표현했지만 당연히 데이터를 조합하여 한 가지 결과를 도출해 낼 수도 있습니다.
        다만 이 부분은 표현 방법이 무궁무진 하여 한 마디로 정리하여 말씀드리긴 어려울 것 같습니다.
        제한적으로 활용할 수 있는 템플릿을 누군가 제공해 준다면 쉽게 할 수도 있겠지만 생각하시는 걸 표현하기엔 부족할 수도 있으므로 결국 직접 만들어 가셔야 할 것 같습니다.

      • 김지연222 2021.11.16 20:11 신고

        감사합니다~

    • 강아지 2021.11.20 20:25

      안녕하세요
      리솔트 결과 값을 한번에 말고
      한개씩 1초간격으로 띄울 수는 없을까요?ㅠㅜ
      답글

      • 아미넴 2021.11.21 20:13 신고

        가능하긴 한데 구조를 좀 변경하여야 합니다. 각각의 결과를 하나씩 div 태그로 묶고 최초에는 보이지 않도록 display none으로 설정한 다음에 그 태그들을 setTimeout 함수를 이용하여 1초 간격으로 fadeIn 하면 괜찮을 듯 싶습니다~

    💲 추천 글