마크업 구조 설정
회원 정보 수집을 위한 폼 요소는 데이터 속성 (data attributes) 을 활용하여 자바스크립트에서 접근성을 높이는 것이 좋다. 각 입력 필드에는 필수 값을 강제하거나 패턴 매칭을 위한 속성을 명시적으로 정의한다.
<div class="auth-wrapper">
<form id="newAccountForm">
<div class="field-group">
<label>아이디</label>
<input type="text" id="reg_id" name="userid" minlength="4" required data-validate="alpha_num">
<span class="msg-display" id="err_reg_id"></span>
</div>
<div class="field-group">
<label>비밀번호</label>
<input type="password" id="reg_pwd" name="password" minlength="8" required data-validate="complex_pwd">
<span class="msg-display" id="err_reg_pwd"></span>
</div>
<div class="field-group">
<label>비밀번호 재확인</label>
<input type="password" id="reg_confirm" name="re_password" required>
<span class="msg-display" id="err_re_pwd"></span>
</div>
<div class="field-group">
<label>이메일 주소</label>
<input type="email" id="reg_email" name="email_address" required>
<span class="msg-display" id="err_mail"></span>
</div>
<button type="submit">계정 생성 완료</button>
</form>
</div>
입력 시 실시간 유효성 검토
사용자가 필드를 조작할 때마다 현재 값의 유효성을 즉시 확인해야 한다. 이를 위해 `input` 이벤트를 바인딩하고, 정규식을 적용하여 조건 위반 여부를 판단한다. 실패 시 오류 메시지를 표시하고 성공 시 클리어한다.
const formInputs = {
reg_id: document.getElementById('reg_id'),
reg_pwd: document.getElementById('reg_pwd'),
reg_confirm: document.getElementById('reg_confirm'),
reg_email: document.getElementById('reg_email')
};
function validateId(e) {
const targetId = 'reg_id';
const errorMsg = document.getElementById(`err_${targetId}`);
const value = e.target.value.trim();
// 대소문자 영문과 숫자, 밑줄 허용
const idPattern = /^[A-Za-z0-9_]+$/;
if (!idPattern.test(value)) {
errorMsg.textContent = '특수 문자는 사용할 수 없습니다.';
} else {
errorMsg.textContent = '';
}
}
function validatePassword(e) {
const targetId = 'reg_pwd';
const errorMsg = document.getElementById(`err_${targetId}`);
const value = e.target.value;
const hasUpper = /[A-Z]/.test(value);
const hasLower = /[a-z]/.test(value);
const hasNum = /[0-9]/.test(value);
if (!hasUpper || !hasLower || !hasNum) {
errorMsg.textContent = '비밀번호는 대소문자와 숫자를 모두 포함해야 합니다.';
} else {
errorMsg.textContent = '';
}
}
// 이벤트 리스너 등록
Object.values(formInputs).forEach(input => {
input.addEventListener('input', (e) => {
if (input.id === 'reg_id') validateId(e);
if (input.id === 'reg_pwd') validatePassword(e);
});
});
폼 제출 전 최종 점검
사용자가 전송 버튼을 클릭하면 기본 동작을 막아야 한다. 모든 필드가 올바르게 작성되었는지 종합적으로 점검하며, 비밀번호 일치 여부 등 상호 의존적 규칙을 여기서 처리한다.
document.getElementById('newAccountForm').addEventListener('submit', function(e) {
e.preventDefault();
let submitAllowed = true;
const idVal = document.getElementById('reg_id').value;
const pwdVal = document.getElementById('reg_pwd').value;
const cfmPwdVal = document.getElementById('reg_confirm').value;
const mailVal = document.getElementById('reg_email').value;
// 아이디 길이 체크
if (idVal.length < 4) {
document.getElementById('err_reg_id').textContent = '아이디는 최소 4 자 이상이어야 합니다.';
submitAllowed = false;
}
// 비밀번호 길이 체크
if (pwdVal.length < 8) {
document.getElementById('err_reg_pwd').textContent = '비밀번호 길이가 부족합니다.';
submitAllowed = false;
}
// 비밀번호 불일치 체크
if (pwdVal !== cfmPwdVal) {
document.getElementById('err_re_pwd').textContent = '비밀번호가 일치하지 않습니다.';
submitAllowed = false;
}
// 이메일 포맷 체크
const mailRegex = /[\w-\.]+@([\w-]+\.)+[\w-]{2,4}/;
if (!mailRegex.test(mailVal)) {
document.getElementById('err_mail').textContent = '올바른 이메일 형식이 아닙니다.';
submitAllowed = false;
}
if (submitAllowed) {
console.log('전송 준비됨: 서버로 데이터 이동');
// this.submit();
}
});
시각적 피드백 스타일링
사용자는 시각적인 힌트를 통해 상태 변화를 알아야 한다. 유효성이 검증된 필드는 녹색 테두리로, 오류가 발생한 필드는 붉은색 테두리와 텍스트로 강조한다.
.msg-display {
color: #e74c3c;
font-size: 12px;
display: block;
margin-top: 4px;
min-height: 1.2em;
}
/* 유효성 검사가 통과된 경우 */
.newAccountForm input:valid {
border-color: #2ecc71;
}
/* 오류 발생 시 */
.newAccountForm input:invalid:not(:placeholder-shown) {
border-color: #e74c3c;
}
서버 연동 아키텍처 점검
중복 계층 검증을 위해서는 백엔드 API 와 통신이 필요하다. 사용자가 입력을 종료했을 때 (`blur`) 호출하여 중복 여부를 서버에서 확인할 수 있다.
document.getElementById('reg_id').addEventListener('blur', async function() {
const userId = this.value;
const errorSpan = document.getElementById('err_reg_id');
if (userId.length >= 4) {
try {
const url = `/api/v1/users/exist?id=${encodeURIComponent(userId)}`;
const res = await fetch(url);
const json = await res.json();
if (json.isUsed) {
errorSpan.textContent = '사용 중인 아이디입니다.';
}
} catch (err) {
console.error('ID 체크 중 오류 발생');
}
} else {
errorSpan.textContent = '';
}
});