학습을 하는 화면은 뭔가 동적인 움직이 있으면 좋을 거 같다. 그래서 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에는 단어별로 학습 횟수를 기록해보자.
'Programming > 온라인 영어암기 단어장 개발' 카테고리의 다른 글
온라인 영어 암기 단어장 만들기(9) - 학습결과 저장하기 (0) | 2025.01.16 |
---|---|
온라인 영어 암기 단어장 만들기(7) - 단어장 저장하기 (0) | 2025.01.13 |
온라인 영어 암기 단어장 만들기(6) - Google Translate API를 활용한 단어 뜻 찾아오기 (0) | 2025.01.11 |
온라인 영어 암기 단어장 만들기(5) - 단어입력화면 만들기 (1) | 2025.01.04 |
온라인 영어 암기 단어장 만들기(4) - 데이터베이스 설계하기 (0) | 2024.12.03 |