최종 HTML 코드 (join.html)
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>회원가입 양식</title>
<link href="join.css" rel="stylesheet">
</head>
<body>
<div id="container">
<form id="form" action="#">
<table class="table">
<tr>
<th>아이디</th>
<td>
<input type="text" name="id" placeholder="아이디" autocomplete="off" required>
</td>
</tr>
<tr>
<th>비밀번호</th>
<td>
<input type="password" name="pw1" placeholder="비밀번호" required>
</td>
</tr>
<tr>
<th>비밀번호 확인</th>
<td>
<input type="password" name="pw2" placeholder="비밀번호 확인" required>
</td>
</tr>
<tr>
<th>이름</th>
<td>
<input type="text" name="name" placeholder="이름" autocomplete="off" required>
</td>
</tr>
<tr>
<th>전화번호</th>
<td>
<input type="text" name="phone" placeholder="전화번호" autocomplete="off" required>
</td>
</tr>
<tr>
<th>원하는 직무</th>
<td>
<select name="position">
<option value="developer">개발자</option>
<option value="designer">웹디자이너</option>
<option value="manager">기획자</option>
<option value="undetermined" selected>미정</option>
</select>
</td>
</tr>
<tr>
<th>성별</th>
<td>
<label>
<input type="radio" name="gender" value="male" checked> 남자
</label>
<label>
<input type="radio" name="gender" value="female"> 여자
</label>
</td>
</tr>
<tr>
<th>이메일</th>
<td>
<input type="email" name="email" placeholder="이메일" title="정확한 메일 주소를 작성해주세요." required>
</td>
</tr>
<tr>
<th>자기소개</th>
<td>
<textarea name="intro" placeholder="자기소개" required></textarea>
</td>
</tr>
</table>
<div class="buttons">
<input type="submit" value="가입" class="btn" title="가입">
<input type="reset" value="리셋" class="btn" title="처음으로">
</div>
</form>
</div>
<script src="join.js"></script>
</body>
</html>
최종 JavaScript 코드 (join.js)
const form = document.getElementById('form');
form.addEventListener('submit', function(event) {
event.preventDefault();
// 폼 데이터 가져오기
let userId = event.target.id.value;
let userPw1 = event.target.pw1.value;
let userPw2 = event.target.pw2.value;
let userName = event.target.name.value;
let userPhone = event.target.phone.value;
let userPosition = event.target.position.value;
let userGender = event.target.gender.value;
let userEmail = event.target.email.value;
let userIntro = event.target.intro.value;
// 아이디 중복 체크 (예시)
const existingIds = ["test123", "user456"]; // 예시로 존재하는 아이디 목록
if (existingIds.includes(userId)) {
alert("이미 사용 중인 아이디입니다.");
return;
}
// 아이디 길이 검사
if (userId.length < 6) {
alert("아이디가 너무 짧습니다. 6자 이상 입력해 주세요.");
return;
}
// 비밀번호 일치 검사
if (userPw1 !== userPw2) {
alert("비밀번호가 일치하지 않습니다.");
return;
}
// 전화번호 형식 체크 (정규식 활용)
const phoneRegex = /^\d{3}-\d{4}-\d{4}$/;
if (!phoneRegex.test(userPhone)) {
alert("전화번호 형식이 올바르지 않습니다. 예시: 010-1234-5678");
return;
}
// 이메일 형식 체크 (정규식 활용)
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/;
if (!emailRegex.test(userEmail)) {
alert("이메일 형식이 올바르지 않습니다.");
return;
}
// 폼 제출 후 애니메이션 효과 적용 (가입 완료 후)
document.body.innerHTML = `
<div class="welcome-message">
<p>${userId}님 환영합니다!</p>
<p>회원 가입 시 입력하신 내역은 다음과 같습니다.</p>
<p>아이디: ${userId}</p>
<p>이름: ${userName}</p>
<p>전화번호: ${userPhone}</p>
<p>원하는 직무: ${userPosition}</p>
</div>
`;
// 애니메이션 효과
document.querySelector('.welcome-message').style.animation = 'fadeIn 2s';
});
// 비밀번호 보이기/숨기기 기능
const pw1 = document.querySelector('input[name="pw1"]');
const pw2 = document.querySelector('input[name="pw2"]');
const togglePw1 = document.createElement('button');
const togglePw2 = document.createElement('button');
togglePw1.innerText = '보이기';
togglePw2.innerText = '보이기';
document.querySelector('tr:nth-child(2) td').appendChild(togglePw1);
document.querySelector('tr:nth-child(3) td').appendChild(togglePw2);
togglePw1.addEventListener('click', function() {
if (pw1.type === 'password') {
pw1.type = 'text';
togglePw1.innerText = '숨기기';
} else {
pw1.type = 'password';
togglePw1.innerText = '보이기';
}
});
togglePw2.addEventListener('click', function() {
if (pw2.type === 'password') {
pw2.type = 'text';
togglePw2.innerText = '숨기기';
} else {
pw2.type = 'password';
togglePw2.innerText = '보이기';
}
});
변경 사항 설명
- 아이디 중복 체크: existingIds 배열에 미리 정의된 아이디 목록을 통해 중복 아이디를 확인합니다. 실제로는 서버와 통신하여 체크할 수 있습니다.
- 전화번호 형식 체크: 전화번호가 XXX-XXXX-XXXX 형식인지 정규식을 이용해 체크합니다.
- 이메일 형식 체크: 이메일 입력 필드는 type="email"로 설정되어 있지만, 정규식을 사용하여 형식을 더 정확히 검증합니다.
- 비밀번호 보이기/숨기기 기능: 비밀번호 입력란 옆에 보이기/숨기기 버튼을 추가하여 사용자가 입력한 비밀번호를 확인할 수 있습니다.
- 폼 제출 후 애니메이션 효과: 가입 후 화면 전환 시 애니메이션을 적용하여 사용자 경험을 향상시킵니다.
Final CSS code
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Arial', sans-serif;
background-color: #f8f8f8;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
padding: 20px;
}
#container {
background-color: white;
border-radius: 10px;
padding: 20px;
width: 100%;
max-width: 400px; /* 최대 너비 400px로 제한 */
max-height: 95vh; /* 폼의 최대 높이 제한 (스크롤 발생하도록) */
box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.1);
overflow-y: auto; /* 세로 스크롤만 허용 */
height: 100%; /* 화면에 꽉 맞도록 설정 */
}
h1 {
text-align: center;
color: #00B894;
margin-bottom: 20px;
font-size: 22px;
}
.table {
width: 100%;
margin-bottom: 15px;
}
th {
text-align: left;
color: #2D3436;
font-size: 14px;
}
td input, td select, td textarea {
width: 100%;
padding: 8px;
border-radius: 5px;
border: 1px solid #ddd;
font-size: 14px;
margin-top: 5px;
background-color: #f1f1f1;
margin-bottom: 12px;
}
input[type="radio"], input[type="checkbox"] {
margin-right: 10px;
}
textarea {
height: 80px;
resize: none;
}
.buttons {
display: flex;
justify-content: space-between;
margin-top: 15px;
}
button, .btn {
padding: 10px 18px;
background-color: #00B894;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 14px;
width: 48%;
transition: background-color 0.3s ease;
}
button:hover, .btn:hover {
background-color: #00C6A1;
}
input[type="radio"]:checked, input[type="checkbox"]:checked {
background-color: #00B894;
color: white;
}
select {
background-color: #f1f1f1;
padding: 8px;
border-radius: 5px;
border: 1px solid #ddd;
}
select:focus {
outline: none;
border-color: #00B894;
}
input:focus, select:focus, textarea:focus {
outline: none;
border-color: #00B894;
box-shadow: 0 0 5px rgba(0, 184, 148, 0.4);
}
.welcome-message {
text-align: center;
font-size: 18px;
margin-top: 20px;
animation: fadeIn 1s ease-in-out;
}
@keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
input[type="submit"]:disabled {
background-color: #BDC3C7;
cursor: not-allowed;
}
/* 성별 버튼 정렬 */
input[type="radio"] {
display: inline-block;
width: 45%;
margin-right: 10px;
vertical-align: middle;
}
input[type="radio"]:last-child {
margin-right: 0;
}
/* 반응형: 화면 크기가 작아지면 폼 크기도 자동 조정 */
@media (max-width: 768px) {
#container {
max-width: 100%;
padding: 15px;
}
h1 {
font-size: 18px;
}
.buttons {
flex-direction: column;
}
.btn {
width: 100%;
margin-bottom: 10px;
}
}
주요 특징:
- 활기차고 깔끔한 디자인: 배경은 연한 회색으로 설정하고, 폼 필드는 부드러운 흰색 배경에 녹색 강조 색상을 추가했습니다.
- 애니메이션: 성공 메시지에 페이드 인 애니메이션을 추가하여 부드러운 전환 효과를 제공합니다.
- 호버 효과: 버튼에 마우스를 올리면 색상이 변경되어 인터랙티브하고 시각적으로 더 매력적으로 만듭니다.
- 모던한 폼 입력: 라운드된 테두리, 포커스 상태, 깔끔한 입력 필드를 통해 현대적인 느낌을 제공합니다.
- 반응형 디자인: 폼은 반응형으로 설정되어 모든 기기에서 잘 보이며, 최대 너비는 400px로 설정했습니다.
'과제' 카테고리의 다른 글
Flask와 Smorest api를 이용한 책 데이터를 관리하는 기능 구현(Flask 2일차) (0) | 2025.04.18 |
---|---|
Flask와 Jinja 템플릿으로 사용자 목록 웹 페이지 만들어보기(Flask 1일차) (0) | 2025.04.17 |
📌Mongo DB 심화 5문제 with python (0) | 2025.03.27 |
페어 과제 (0) | 2025.03.24 |
Database- 데이터베이스 (문제풀이 3일차_심화) (0) | 2025.03.21 |