
1. UI / UX

기본적으로 화면의 비율에 따라 엘리먼트들의 사이즈나 위치를 보기 쉽게하였다. 이번 프로젝트에서는 flex-direction을 설정하여 반응형 웹을 구현했다.
TO DO LIST를 사용할 때 시간을 보면 조급해지는 사용자들이 많기도 해서 hover를 사용하여 마우스를 올렸을 때만 보여지게끔 구현했다.
hover를 구현했을 시에 PC환경에서는 작동이 잘되었지만, 모바일에서는 마우스가 없기 때문에 작동이 안됐다. 이를 해결하기 위해 media query를 사용하였다. 코드는 아래와 같다.
@media (hover: hover) and (pointer: fine){
#date_box{
filter: blur(10px);
-webkit-filter: blur(10px);
transition: filter 1.5s;
}
#date_box:hover{
filter: blur(0);
-webkit-filter: blur(0);
transition: filter 1.5s;
}
}
@media (hover: none) and (pointer: coarse){
#date_box{
filter: blur(0px);
-webkit-filter: blur(0px);
}
}
@media (hover: hover)는 포인팅 장치가 쉽게 hover 할 수 있는 경우를 말하고, @media(hover: none)은 포인팅 장치가 hover를 지원하지 않는 경우를 말한다.
추가적으로 모바일에서 길게 누를 시 hover로 인식하는 경우가 있는데 이는 hover: none 으로 판단된다.
@media 뒤에 위치한 pointer는 포인팅 장치의 정확성에 따라 조금 더 자세하게 설정할 수 있게 한다.
하지만 요즘은 키보드와 마우스를 추가할 수 있는 테블릿 또는 터치스크린을 지원하는 PC 등 모바일과 PC의 구분성이 점점 모호해져 위의 media query로 구분하기에 어려움이 많을 것 같다.
이를 보완해줄 새로운 기능이 나오기 전까진 모바일과 PC의 통일성을 위해 자제할 필요가 있을 것 같다.
혹시나 이미 이 부분을 보완할 수 있는 좋은 방법이 있다면 추후에 추가하겠다.


TO DO LIST에서 LIST의 완료 유무를 나타낼 수 있게 Input checkbox로 구현했다.
체크박스의 기본 모양은 사진의 좌측과 같다.
체크박스를 커스텀하는 방법은 다양하지만, html의 정보성과 접근성을 위해 체크박스를 유지하고 Label과 가상요소 ::after를 사용하여 커스텀했다.
Label은 사용자 인터페이스 항목의 설명을 나타낸다. 쉽게 말해 Input 만 사용하면 사용자가 Input에 정확히 초점을 맞춰야하지만, label을 사용하면 Label의 영역을 클릭해도 Input에 초점이 맞춰져 사용성을 높여준다. 또한 스크린 리더 기능을 사용할 시에도 Input에 대한 정보를 알려준다.
Label을 사용하는 방법은 label의 for 속성에 Input ID 값을 넣어 사용하는 것과 Label 내부에 Input을 중첩시켜 암시적으로 사용하는 것이 있다.
TO DO LIST 특성 상 Input에 ID 값을 주게 되면 ID가 중복되기에 Label 내부에 Input을 중첩시켜 사용하였다.
아래는 가상요소 :: after를 사용하여 체크박스의 프레임과 체크모양을 구현한 코드이다.
label .divbox{
display: block;
width: 1.5rem;
height: 1.5rem;
position: relative;
border: 2px solid #000000;
background-color: #ffffff;
cursor: pointer;
}
label .divbox::after{
display: block;
content: '';
position: relative;
border: solid #02da46;
border-width: 0 3px 3px 0;
width: 0.5rem;
height: 1rem;
transform: rotate(45deg);
left: 4px;
bottom: 2px;
opacity: 0;
}
label input[type='checkbox']:checked + div::after{
opacity: 1;
}
Label divbox로 기본 프레임을 만들어주었고, divbox::after를 사용해 체크모양을 만들어줬다. 또한 opacity를 통해 Input 체크 전 후를 표현했다.
2. JS 주요 기능
현재 날짜와 시간을 가져오기 위해 get 매서드를 사용하였다.
여기서 getDay()를 가져오면 0~6까지의 진수를 가져오기때문에 우리가 보기 쉬운 요일을 넣은 배열을 만들고 진수를 index에 넣어 불러오는 방법을 사용했다. 또한 getMonth()는 1월부터 12월을 0~11의 진수로 가져오기에 getMonth() +1한 값을 month 변수에 할당해주어서 해결하였다.
마지막으로 현재 시간을 실시간으로 보여주기 위해 setInterval 함수를 사용해 1000밀리초마다 함수를 실행한다.
let nowtime = document.getElementById("nowtime");
let today = document.getElementById("today");
function outputdate(){
let nowdate = new Date();
let nowday = ["일요일","월요일", "화요일","수요일","목요일","금요일","토요일"]
let year = nowdate.getFullYear();
let month = nowdate.getMonth() +1;
let date = nowdate.getDate();
let day = nowdate.getDay();
let hours = nowdate.getHours();
let minutes = nowdate.getMinutes();
let seconds = nowdate.getSeconds();
today.innerHTML = year+"년 " + month+"월 " + date+"일 " + nowday[day];
nowtime.innerHTML = hours+" : " + minutes+" : " + seconds+" ";
};
outputdate();
setInterval(outputdate, 1000);
아날로그 시계를 구현하기 위해 css의 border로 표현한 시침,분침,초침에 각각의 현재 시간 별 각도를 계산해 넣었다. 각도는 총 360도에 12시간, 60분, 60초로 나누어지는 수를 나누어 현재 시간만큼 곱하여 계산했다.
시과 분은 자연스러운 시간 흐름을 표현하기 위해 각각 분과 초의 각도를 더하였다.
function analogclock() {
let now = new Date();
let hour = document.getElementById('hour');
let min = document.getElementById('min');
let sec = document.getElementById('sec');
let h = now.getHours();
let m = now.getMinutes();
let s = now.getSeconds();
let degH = h * (360 /12) + m * (360 / 12 / 60);
let degM = m * (360 / 60) + s * (360 / 60 /60);
let degS = s * (360 / 60);
hour.style.transform = `rotate(${degH}deg)`;
min.style.transform = `rotate(${degM}deg)`;
sec.style.transform = `rotate(${degS}deg)`;
};
analogclock();
setInterval(analogclock, 1000);
TO DO LIST의 등록은 필요한 요소를 생성한 후 INPUT text value와 함께 appendChild를 사용하여 list에 넣었다.
그리고 LIST 삭제는 삭제를 나타내는 이모지를 넣은 후, 이모지 클릭 시 parentElement.remove()를 사용하여 구현했다. 여기서 각 이모지에 해당하는 부모요소를 삭제하기 위해 event.target을 사용하였다.
//To_do_list 등록
let todolist = document.getElementById("todolist");
let inputtext = document.getElementById("text");
let form = document.getElementById("form");
function listup(text){
let li = document.createElement("li");
let delbtn = document.createElement("span");
let check = document.createElement("input");
let checklabel = document.createElement("label");
let checkbox = document.createElement("div");
let listtext = document.createElement("div");
if(text.trim() !== ''){
li.appendChild(checklabel);
checklabel.appendChild(check);
check.setAttribute("type","checkbox");
check.setAttribute("class","classcheck");
check.setAttribute("name","checkbox");
checklabel.appendChild(checkbox);
checkbox.setAttribute("class","divbox");
listtext.appendChild(document.createTextNode(inputtext.value));
li.appendChild(listtext);
listtext.setAttribute("class","listtext")
check.addEventListener('change', function () {
listtext.classList.toggle('checked', check.checked);
});
delbtn.innerText = "❌";
delbtn.addEventListener('click', listdel);
li.appendChild(delbtn);
todolist.appendChild(li);
}
else{
alert("입력하세요")
};
};
//To_do_list 삭제
function listdel(event){
event.target.parentElement.remove();
};
////To_do_list 실행
function upload(event){
event.preventDefault();
listup(inputtext.value);
inputtext.value = "";
}
form.addEventListener('submit', upload);
3. 느낀점
자바스크립트를 이용한 첫 토이프로젝인만큼 이론으로만 학습한 자바스크립트를 프로젝트에 바로 적용하는 것이 어려웠다. 더 많은 토이프로젝트를 만들어보면서 자바스크립트의 활용하는 것을 익혀야함을 느꼈다. 아직까진 어떤 코드가 잘 짜여진 코드인지 구분할 수 없지만 최대한 중복되지 않는 코드와 나중에 봐도 한 눈에 알 수 있게 해야함을 항상 생각하고 코드를 짜야겠다.