제출한 웹 로또 링크
https://dev-dino22.github.io/javascript-lotto/
1차 시도
실시간 input Event로 유효성 검사로 유효한 값을 입력할 때까지 통과되지 않은 로직을 빨간색 에러로 표시
제공된 기본 로또 UI 시안의 경우, 사용자가 구매금액을 얼마를 입력해야하는지, 로또 당첨번호의 숫자 범위는 어디까지인지 등, 유효값을 직관적으로 알기 힘든 한계가 있다고 생각.
-> 그래서 사용자의 input 이벤트를 실시간 감지하여 유효값을 검사해주는 로직이 있으면 좋겠다.
-> 그래서 처음엔 빨간글씨로 유효하지 않은 이유를 렌더링하고 유효한 값이 모두 입력될 시, 검증 문구가 사라지도록 설계
-> 그런데, 크루들과 부모님께 사용자 경험을 물었더니 "아직 다 치지도 않았는데 빨간 글씨 뜨는 게 기분 나쁘다.", "검증 문구가 생겼다 사라졌다 하면서 박스가 움직이는 게 거슬린다" 등의 피드백을 받음
-> 그래서 아래와 같이 다시 UI를 재구성하였음
2차 시도
회색 글씨로 유효값 안내 문구를 기본으로 띄우고 해당 유효값을 충족할 시 X 표시가 V 표시가 되도록 변경
또한 구입 입력 금액 폼의 경우, 유효한 값을 입력할 때까지 disabled 처리를 해놓았으며, 구입이 진행된 후 추가구매를 할 수 없도록 이 역시 disabled 처리
결과확인 버튼의 경우에는 따로 disabled 처리를 하지 않고 유효하지 않은 채로 버튼 클릭 시 안내 문구를 다시 확인해달라는 alert을 띄움.
왜냐하면, 구입 금액 버튼도 디세이블 처리된 상태인데 복잡한 유효값을 만족할 때까지 결과 확인 버튼도 disabled 되어있는 것이 사용자에게 답답함을 야기시킬 것 같았다.
발행된 로또 리스트를 클릭하면, 클릭한 요소의 로또 번호가 복사됨
그리고 당첨번호 필드에 붙여넣으면 자동으로 스플릿되어 필드값이 채워짐
이러한 기능을 위해 ','과 공백을 받아 처리를 해주어야해서 input 태그는 number 타입이 아닌 text 타입으로 해두고 0-9 숫자와 ','.' ' 이 아닌 입력 시 입력값이 지워지도록 따로 구현함
모달의 경우 엑스 버튼과 더불어 'esc 키 입력','모달창 밖 배경 클릭' 시에도 모달이 닫히도록 구현
class ClickEvent {
constructor(elem) {
elem.addEventListener("click", this.onClick.bind(this));
}
reload() {
location.reload();
}
showModal(element) {
if (!element) return;
document.getElementById("modalBackground")?.classList.add("show");
}
removeModal(element) {
if (element.id === "modalBackground" || element.id === "closeModalBtn") {
document.getElementById("modalBackground")?.classList.remove("show");
return;
}
}
...
onClick(event) {
let target = event.target.closest("[data-action]");
if (!target) return;
if (
target.dataset.action &&
typeof this[target.dataset.action] === "function"
)
this[target.dataset.action](target);
}
}
new ClickEvent(document);
저의 로또페이지의 경우, ['click', 'input', 'submit'] 의 이벤트리스너 등록이 많은 영역에서 필요했습니다. 이러한 이벤트리스너를 모든 요소마다 새로 등록하는 것이 비용이 너무 많이 드는 로직인 것 같아 이벤트 위임의 방식을 이용해 위 코드처럼 document 단위에서 최초 한 번 이벤트 리스너를 등록해두고 이벤트 종류 별로 클래스를 만들어 한 곳에서 관리하고 사용할 요소에 data-* 속성을 추가해주었습니다.
구현에 과 cloneNode() 를 이용해 innerHTML 사용 지양
<template id="modalTemplate">
<div class="modal-box" id="modalBox">
<div class="modal-content">
<div class="close-modal-btn-box">
<div class="close-modal-btn" id="closeModalBtn" data-action="removeModal">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14 1.41L12.59 0L7 5.59L1.41 0L0 1.41L5.59 7L0 12.59L1.41 14L7 8.41L12.59 14L14 12.59L8.41 7L14 1.41Z" fill="black"/>
</svg>
</div>
</div>
<h2>🏆 당첨 통계 🏆</h2>
<table>
function openModal() {
const modalBackground = getHTML("modalBackground");
if (modalBackground.querySelector(".modal-box")) {
modalBackground.classList.add("show");
return;
}
const modalClone = getHTML("modalTemplate").content.cloneNode(true);
getHTML("modalBackground").appendChild(modalClone);
getHTML("modalBackground").classList.add("show");
}
기존에는 innerHTML을 사용해 모달을 추가하는 방식이 많았지만, 보안 문제(XSS) 및 성능 문제로 인해 innerHTML을 지양하는 것이 좋다고 판단했습니다.
대신 을 활용하여 cloneNode()를 사용하면, 보다 안전하고 효율적으로 동적으로 요소를 추가할 수 있습니다.
createElement 대신 template 태그를 활용한 이유는, 동적으로 변경되는 부분이 크지 않고 단순 결과를 출력하는 모달의 정적 폼이 외부에 아예 노출되면 안되는 부분은 아니라고 생각해서 createElement보다 비용이 적은 template 방식이 더 적합하다고 생각했습니다.
또한 기존에 모달이 열려 있는 경우 새로 추가하는 것이 아니라, 기존 모달을 다시 활성화하는 방식으로 수정하여 불필요한 DOM 추가를 방지했습니다.
이제 노드환경에서 브라우저로 넘어와 UI를 그리게된만큼, 가장 많이 고민한 점은 사용자 경험이었습니다.
이 로또 페이지를 실제로 서비스하게된다면, 사용자로서 어떤 부분이 불편하고 어떤 기능이 추가되었으면 좋겠는지를 생각하면서 요구 기능 이상의 편의성 기능들을 추가했습니다. 그로 인해, 프로그램이 다소 무거워지고 아직 역량부족으로 코드가 지저분해진 부분이 있습니다. 또한, 이러한 고민과 시도들을 적용하느라, 정작 도메인 로직 리팩토링에는 부실했던 것 같아 아쉬웠습니다.
또한 이러한 UI 로직에 개발 시간 기회비용을 많이 소모하느라 디렉터리 구조나 상수화도 신경써 진행하지 못하였습니다🥲
이번 구현 과정에서 고민했던 사항과 더 나은 방향을 찾고 싶은 부분들이 있습니다.
1️⃣ UI 개선과 코드 구조화의 균형
UI/UX를 개선하면서 사용자 경험을 향상시키는 데 많은 시간을 투자했지만, 도메인 로직 리팩토링과 코드 구조화에는 상대적으로 부족함이 있었다고 느꼈습니다.
특히,
이벤트 리스너 최적화(이벤트 위임 방식 도입)
모달, 입력값 검증 로직 분리
불필요한 DOM 탐색 제거
등의 개선을 했지만, 더 효과적인 방식이 있을지 궁금합니다.
👉 질문:
현재 UI 중심으로 작성된 코드가 지나치게 무거워졌다고 느끼는데, UX를 유지하면서도 코드 구조를 더 정리할 방법이 있을까요?
UX 를 위해 추가 기능이 늘어날 수록 코드가 무거워지는데 여기서 UX냐 코드 최적화냐를 판단하는 기준이 있는지 궁금합니다.
2️⃣ 유효성 검사 로직 개선 방향
유효성 검증을 개선하면서 input 이벤트를 실시간 감지하여 사용자가 유효한 값을 입력하도록 유도하는 방식을 도입했습니다.
하지만,
검증 로직이 점점 복잡해지는 문제가 있음
실시간으로 유효성을 검사하는 것이 성능적으로 부담이 될 가능성
👉 질문:
현재는 X/✔ 아이콘으로 즉각적인 피드백을 주고 있는데, 이러한 실시간 피드백보다 blur() 처리됐을 때만 하는 게 비용과 타협했을 때 더 적절한 선택인지, 과도한 처리였는지 리뷰어님의 생각이 궁금합니다!
3️⃣ 최적화할 수 있는 부분 (렌더링 성능, 이벤트 핸들링 등)
현재 UI 이벤트가 많아지면서,
불필요한 리렌더링 발생 가능성
모달, 입력 필드 등에서 불필요한 DOM 조작이 있을 수 있음
각종 이벤트 리스너에서 더 최적화할 부분이 있는지 고민
👉 질문:
현재 코드에서 불필요한 렌더링이나 이벤트 리스너 호출을 더 줄일 방법이 있을까요?
입력값 자동 채우기, 모달 관리 방식 등에서 성능 최적화할 부분이 있다면 어떤 방식이 효과적일까요?
<template><script> : difer, async, module