Programming/온라인 영어암기 단어장 개발

온라인 영어 암기 단어장 만들기(8) - 학습화면 만들기

juhpark 2025. 1. 16. 20:21

학습을 하는 화면은 뭔가 동적인 움직이 있으면 좋을 거 같다. 그래서 CSS 에니메이션을 테스트해 보고 코드를 만들어 주는 다음 사이트를 활용하여 구현하였다. Animista 사이트 안에서는 원하는 에니메이션을 선택하면 움직임을 바로 보여주어 테스트 해보고 원하는 에니메이션의 코드를 바로 보여주어 적용할 수 있다. 

 

Animista - On-Demand CSS Animations Library

Animista is a CSS animation library and a place where you can play with a collection of ready-made CSS animations and download only those you will use.

animista.net

 

너무 현란한 움직임은 학습에 도움이 되지 않을 것 같아서 조금 심플한 (ENTRANCE-SLIDE-IN) 효과만 사용하였다. 공부를 시작하면 학습카드가 오른쪽에서 나오고, 학습이 끝나면 왼쪽으로 사라지는 효과를 주었다.

    .study_card_container_hide, .quiz_card_container_hide{
        -webkit-animation: slide-out-left 0.2s cubic-bezier(0.755, 0.050, 0.855, 0.060) both;
        animation: slide-out-left 0.2s cubic-bezier(0.755, 0.050, 0.855, 0.060) both;
    }
    .study_card_container_show, .quiz_card_container_show {
        -webkit-animation: slide-in-right 0.4s cubic-bezier(0.390, 0.575, 0.565, 1.000) both;
        animation: slide-in-right 0.4s cubic-bezier(0.390, 0.575, 0.565, 1.000) both;
    }
    
  /* Animista에서 자동 생성된 코드 */  
  @-webkit-keyframes slide-out-left {
    0% {-webkit-transform: translateX(0);transform: translateX(0);
      opacity: 1;}
    100% {-webkit-transform: translateX(-1000px);transform: translateX(-1000px);
      opacity: 0;}
  }
  @keyframes slide-out-left {
    0% {-webkit-transform: translateX(0);transform: translateX(0);
      opacity: 1;}
    100% {-webkit-transform: translateX(-1000px);transform: translateX(-1000px);
      opacity: 0;}
  }

  @-webkit-keyframes slide-in-right {
    0% {-webkit-transform: translateX(1000px);transform: translateX(1000px);
      opacity: 0;}
    100% {-webkit-transform: translateX(0px);transform: translateX(0px);
      opacity: 1;}
  }
  @keyframes slide-in-right {
    0% {-webkit-transform: translateX(1000px);transform: translateX(1000px);
      opacity: 0;}
    100% {-webkit-transform: translateX(0);transform: translateX(0);
      opacity: 1;}
  }

 

단어학습 목록 페이지에서 한개의 항목을 선택하면, 바로 학습화면(study.html)으로 전환을 한다. 이때 필요한 파라메터는 word_set의 _id 값을 id에 get 방식으로 데이터를 넘겼다. html의 자바스크립트에서만 모든걸 해걸하고 싶어서 URL에서 파라메터를 뽑아내는 Request 객체를 만들어 사용하였다. 아래 소스를 별도 util.js에 넣고 script로 불러왔다.

var Request = function(){
    this.getParameter = function(name){
        var rtnval = '';
        var nowAddress = unescape(location.href);
        var parameters = (nowAddress.slice(nowAddress.indexOf('?')+1, nowAddress.length)).split('&');
        for(var i=0; i<parameters.length; i++){
            var varName = parameters[i].split('=')[0];
            if(varName.toUpperCase() == name.toUpperCase()){
                rtnval = parameters[i].split('=')[1];
                break;
            }
        }
        return rtnval;
    }
}
var request = new Request();

 

실제 사용하는 방법은 아래와 같이 간단하다. javac 나 nodejs에서처럼 id를 손쉽게 가져 올수 있다.

var id = request.getParameter('id');

 

위 id값으로 학습 데이터를 가져오는 router 를 생성하였다.  ws_rel_model의 두 필드 word_set_id, word_id는 각각 word_set, word객체를 참조하는 형태로 되어 있기에, find().populate() 와 같은 행태로 3개의 collection을 조인할 수 있다.

const mongoose = require('mongoose');
const { ObjectId } = mongoose.Types;
const { Schema } = mongoose;    

const user_model     = 
      mongoose.models['user']||
      mongoose.model('user', 
                     new Schema({user_id:{type:String, unique:true, required: true}, 
                                 pw:{type:String, required:true}, 
                                 email:{type:String, required:true}}, { strict: false }));

const word_set_model = 
      mongoose.models['word_set']||
      mongoose.model('word_set'    , 
                      new Schema({user_id:{type:String, required:true},
                                  title:{type:String, required:true}}, 
                                  { strict: false }));

const ws_rel_model=    
      mongoose.models['ws_rel_model']||
      mongoose.model('ws_rel_model', 
                      new Schema({user_id:{type:String, required:true}, 
                                  word_set_id:{type:Schema.Types.ObjectId,ref:"word_set"}, 
                                  word_id:{type:Schema.Types.ObjectId,ref:"word"}}, 
                                  { strict: false })); 

const word_model     = 
      mongoose.models['word']||
      mongoose.model('word'        , 
                      new Schema({w:{type:String, required:true, unique: true}, 
                                  m:{type:String, required:true}}, 
                                  { strict: false })); 


router.get('/word_set', async(req, res) => { 
    console.log(req.session.username)
    if(req.session.username == undefined|| req.session.username==""){ 
        res.json({isLogin:false, state:'success', message:''})
    }else{
        var result = await ws_rel_model.find(
                         {user_id: req.session.username, word_set_id: req.query.id}
                     ).populate('word_id word_set_id')
        console.log(result)
        res.json({isLogin:true, user_id: req.session.username, 
                  state:'success', data:result, message:''})  
    }      
})

 

find()는 user_id와 word_set_id로 조회를 하고, populate에는 "word_set word" 와 같은 스트링만 입력하면 자동으로 조인되어 아래와 같은 데이터를 출력해 준다.

{
  "isLogin":true,"user_id":"juhpark","state":"success",
  "data":[
       {"_id":"678513533b358b086979c558",
        "user_id":"juhpark",
        "word_set_id": {"_id":"678513533b358b086979c555",
                        "user_id":"juhpark",
                        "title":"11월",
                        "__v":0},
         "word_id":{"_id":"678276859a30d5d1ddce7f0d",
                    "w":"sky",
                    "m":"하늘","__v":0},"__v":0}
         },                    
         { ... },
         { ... }
    ],
   "message":""
 }

 

study.html 안에서 위 데이터를 호출하는 소스는 다음과 같다. data객체에 원하는 형태로 데이터를 담고,  완료되면 study_next_word() 함수를 호출하여 학습을 시작한다.

var obj={}
obj['id'] = id
$.get('/word/word_set', obj, function(d){
    if(d.data.length>0){ 
        /* data 객체에 원하는 형태로 담기 */
        data['id'] = d.data[0]._id
        data['user_id'] = d.user_id
        data['title'] = d.data[0].word_set_id.title
        data['word'] = new Array();
        d.data.forEach(function(w){
            console.log(w)
            data['word'].push({id: w.word_id._id, w:w.word_id.w, m:w.word_id.m})
        })
        study_next_word()  /* 학습데이터를 보여주는 로직 */
    }else{
        alert("조회된 자료가 없습니다.")
        location.href="/list.html"
    }
})

 

클릭, Enter, Space  등으로 해당카드를 선택하면, 가려진 녹색 창이 사라지고 뜻이 나오고 한번더 선택하면 카드가 왼쪽으로 사라지고 오른쪽에서 다음카드가 나타난다.

 

 

다음 작업으로는 학습이 끝났을때, 학습결과를 저장할 예정이다. 단어장을 다 끝냈을때만, word_set에 횟수를 기록하고 ws_rel_model에는 단어별로 학습 횟수를 기록해보자.