티스토리 뷰

간단한 회원가입 페이지

 

1. 개요

 주어진 과제는 간단한 회원가입 페이지를 디자인하는 것이다. 주어진 항목으로는 아이디(username), 비밀번호(password), 비밀번호 확인(password-retype), 회원가입 버튼이 있다. 그리고 이번 과제 구현을 위해 깃헙의 signup 페이지를 참고하기로 하였다.

참고할 페이지

2. 와이어프레임

 위의 사진을 크게 5부분으로 나누었다. 위에서부터 순서대로 인사말이 적혀져있는 부분, 아이디를 입력하는 부분, 비밀번호를 입력하는 부분, 비밀번호를 다시 한 번 확인하는 부분, 마지막으로 회원가입 버튼이 있는 부분과 같이 나누었다. 그리고 제일 위의 인사말 두 줄은 h2를 두 개 이용해 표현하였으며 각 input이 있는 부분은 title 부분과 input 부분으로 또 다시 나누었다. 마지막으로 join 버튼이 있는 부분은 title과 버튼을 같은 위치에 두기로 하였다.

3. html, css


<!DOCTYPE html>
<html lang="en">
<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" />
<link rel="stylesheet" href="validation.css" />
<script src="functions.js"></script>
<title>Document</title>
</head>
<body>
<div id="main">
<div id="wrapper">
<div id="greetings">
<h2 class="greeting">Welcome!</h2>
<h2 class="greeting">Let’s begin the adventure</h2>
</div>
<div class="input-field show-field" id="username-field">
<h2 class="title">Enter your username</h2>
<form class="input-line">
<span class="input-icon">👉</span>
<input
type="text"
class="username"
placeholder="Username을 입력하세요."
/>
<button id="username-btn" class="submit-btn">Continue</button>
</form>
</div>
<div id="password-field" class="input-field field-hide">
<h2 class="title">Enter your Password</h2>
<form class="input-line">
<span class="input-icon">👉</span>
<input
type="password"
class="password"
placeholder="비밀번호를 입력하세요."
/>
<button id="password-btn" class="submit-btn">Continue</button>
</form>
</div>
<div id="password-confirmation-field" class="input-field field-hide">
<h2 class="title">Enter your Password again</h2>
<form class="input-line">
<span class="input-icon">👉</span>
<input
type="password"
class="password-retype"
placeholder="비밀번호를 다시 입력하세요."
/>
<button id="password-confirmation-btn" class="submit-btn">
Continue
</button>
</form>
</div>
<form class="join-field field-hide">
<h2 class="title">Let's join us!</h2>
<div class="submit-btn join-btn">Join!</div>
</form>
<p id="wrong-id-msg" class="error-msg msg-hide">
ID는 4글자 이상이어야 합니다.
</p>
<p id="wrong-password-msg" class="error-msg msg-hide">
Password는 8글자 이상이어야 합니다.
</p>
<p id="password-mismatch-msg" class="error-msg msg-hide">
Password의 확인이 올바르지 않습니다.
</p>
</div>
</div>
</body>
<script src="validation.js"></script>
</html>
view raw validation.html hosted with ❤ by GitHub

@import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@300;400&display=swap");
html,
body,
div,
span,
applet,
object,
iframe,
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote,
pre,
a,
abbr,
acronym,
address,
big,
cite,
code,
del,
dfn,
em,
img,
ins,
kbd,
q,
s,
samp,
small,
strike,
strong,
sub,
sup,
tt,
var,
b,
u,
i,
center,
dl,
dt,
dd,
menu,
ol,
ul,
li,
fieldset,
form,
label,
legend,
table,
caption,
tbody,
tfoot,
thead,
tr,
th,
td,
article,
aside,
canvas,
details,
embed,
figure,
figcaption,
footer,
header,
hgroup,
main,
menu,
nav,
output,
ruby,
section,
summary,
time,
mark,
audio,
video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
main,
menu,
nav,
section {
display: block;
}
/* HTML5 hidden-attribute fix for newer browsers */
*[hidden] {
display: none;
}
body {
line-height: 1;
}
menu,
ol,
ul {
list-style: none;
}
blockquote,
q {
quotes: none;
}
blockquote:before,
blockquote:after,
q:before,
q:after {
content: "";
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
* {
box-sizing: border-box;
}
body {
font-weight: 300;
font-family: "Source Sans Pro", sans-serif;
line-height: 1.2;
background-color: black;
}
a {
text-decoration: none;
color: inherit;
}
:root {
--greeting-color: #607394;
--bg-color: #0c162c;
--title-color: #00cec7;
--btn-color: #1d5d3f;
}
@keyframes type {
from {
width: 0;
}
}
@keyframes showField {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
#main {
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
#wrapper {
width: 40vw;
height: 80vh;
display: flex;
flex-direction: column;
position: relative;
}
#greetings {
flex: 1 0 0;
display: flex;
flex-direction: column;
justify-content: center;
padding: 20px;
}
.greeting {
color: var(--greeting-color);
font-size: 20px;
font-weight: bold;
white-space: nowrap;
overflow: hidden;
width: 30em;
animation: type 4s steps(60, end);
}
.input-field {
flex: 1 0 0;
display: grid;
grid-template-rows: 1fr 1fr;
padding: 20px;
transition-duration: 10s;
}
.show-field {
animation: showField 1s linear;
}
.title {
color: var(--title-color);
font-size: 20px;
font-weight: bold;
}
.input-line {
display: flex;
align-items: center;
position: relative;
}
.input-icon {
font-size: 30px;
}
input {
background-color: var(--bg-color);
border: none;
width: 70%;
height: 90%;
margin: 0 20px;
padding-left: 20px;
color: white;
}
.submit-btn {
border: 3px solid var(--btn-color);
background-color: transparent;
color: var(--btn-color);
border-radius: 15px;
font-weight: bold;
width: 20%;
height: 90%;
display: flex;
justify-content: center;
align-items: center;
}
.join-btn {
width: 20%;
height: 50%;
}
.join-field {
flex: 1 0 0;
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px;
}
.error-msg {
position: absolute;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
font-size: 20px;
font-weight: bold;
color: red;
margin: 0 auto;
}
.msg-hide {
display: none;
}
.field-hide {
visibility: hidden;
}
view raw validation.css hosted with ❤ by GitHub

 


 우선 전체적인 틀은 div#wrapper를 이용해 하나로 합쳤다. 그리고 div#wrapper의 position은 relative로 주었는데, 이는 후술할 에러 메세지의 위치 때문이다. 각각의 영역은 'flex: 1 0 0;'을 통해 모두 같은 높이를 갖게 하였다. 또한, 적절한 padding 값을 통해 각 영역 속의 요소들이 지나치게 borderd에 붙어 표시되는 것을 방지하였다. 주어진 과제에서 아이디의 글자가 4글자 미만이거나 비밀번호 확인이 틀릴 경우 에러 메세지가 표시되는데 이 에러 메세지 또한 html 코드로 작성하였다. 그리고 이 떄의 에러 메세지는 어느 상황에서든 div#wrapper의 상단에 표시되기를 원했으며 이를 'position: absolute;'을 통해 구현하였다. 그리고 최상단의 인사말은 한 글자씩 표시되게 하기 위해 stackoverflow의 글을 참고해, type이라는 keyframe과 white-space, overflow, width 값을 이용해 구현하였다.(https://stackoverflow.com/questions/33486228/how-to-reveal-one-letter-at-a-time) 그리고 각 input 영역은 천천히 등장하게 하기 위해 @keyframe showField와 animation을 이용하였다.

 

4. JS


const usernameBtn = document.querySelector("#username-btn");
const passwordBtn = document.querySelector("#password-btn");
const passwordCfmBtn = document.querySelector("#password-confirmation-btn");
const wrongIdMsg = document.querySelector("#wrong-id-msg");
const wrongPasswordMsg = document.querySelector("#wrong-password-msg");
const passwordMismatchMsg = document.querySelector("#password-mismatch-msg");
const passwordField = document.querySelector("#password-field");
const passwordCfmField = document.querySelector("#password-confirmation-field");
const joinField = document.querySelector(".join-field");
const username = document.querySelector(".username");
const password = document.querySelector(".password");
const passwordCfm = document.querySelector(".password-retype");
const joinBTn = document.querySelector(".join-btn");
const beforePassIcon = "👉";
const afterPassIcon = "👍🏻";
function isMoreThan4Length(value) {
return value.length >= 4;
}
function isMatch(password1, password2) {
return password1 === password2;
}
const hideAllErrorMsg = () => {
wrongIdMsg.classList.add("msg-hide");
wrongPasswordMsg.classList.add("msg-hide");
passwordMismatchMsg.classList.add("msg-hide");
};
const handleUsernameBtnClicked = () => {
event.preventDefault();
if (isMoreThan4Length(username.value)) {
// 아이디 필드의 버튼 텍스트 변경
usernameBtn.textContent = "Clear!";
// 아이디 입력 아이콘 변경
document.querySelector(
"#username-field .input-line .input-icon"
).textContent = afterPassIcon;
// 아이디 입력 불가능하게
username.setAttribute("disabled", true);
// 에러 메세지들 전부 삭제
hideAllErrorMsg();
// 비밀번호 입력 필드 표시
passwordField.classList.remove("field-hide");
passwordField.classList.add("show-field");
} else {
// 아이디 글자 수를 충족하지 못했다고 알림
wrongIdMsg.classList.remove("msg-hide");
}
};
const handlePasswordBtnClicked = () => {
event.preventDefault();
if (password.value.length >= 8) {
passwordBtn.textContent = "Clear!";
document.querySelector(
"#password-field .input-line .input-icon"
).textContent = afterPassIcon;
password.setAttribute("disabled", true);
hideAllErrorMsg();
passwordCfmField.classList.remove("field-hide");
passwordCfmField.classList.add("show-field");
} else {
wrongPasswordMsg.classList.remove("msg-hide");
}
};
const handlePasswordCfmBtnClicked = () => {
event.preventDefault();
if (isMatch(password.value, passwordCfm.value)) {
passwordCfmBtn.textContent = "Clear!";
document.querySelector(
"#password-confirmation-field .input-line .input-icon"
).textContent = afterPassIcon;
passwordCfm.setAttribute("disabled", true);
hideAllErrorMsg();
joinField.classList.remove("field-hide");
joinField.classList.add("show-field");
} else {
passwordMismatchMsg.classList.remove("msg-hide");
}
};
const handleJoinBtnClicked = () => {
alert("회원가입을 축하드립니다!");
};
usernameBtn.addEventListener("click", handleUsernameBtnClicked);
passwordBtn.addEventListener("click", handlePasswordBtnClicked);
passwordCfmBtn.addEventListener("click", handlePasswordCfmBtnClicked);
joinBTn.addEventListener("click", handleJoinBtnClicked);
view raw validation.js hosted with ❤ by GitHub

 자바스크립트 코드는 document.querySelector를 이용해 각각 필요한 것들을 불러온 후, 각각의 버튼이 클릭될 때마다 그 상황에 맞는 함수를 실행시킨다. 그리고 각각의 버튼에 해당하는 함수들의 내용은 거의 비슷하다. 예를 들어, username 버튼을 클릭하였을 경우, username이 특정한 조건을 충족하는지 체크한다. 이번 코드에서는 단순히 username의 길이가 4 이상인지만 검사한다. 그래서 만약 이 조건을 충족한다면 아이디 입력 영역의 아이콘과 버튼 텍스트를 변경하고, input을 변경 불가능하게 바꾼 후 비밀번호 입력 영역을 표시한다. 만약 조건을 충족하지 못한다면 이에 해당하는 에러 메세지를 띄운다.

 

5. 결과

'코드스테이츠 부트캠프' 카테고리의 다른 글

고차함수, 내장고차함수  (0) 2023.01.12
Section 01 회고  (0) 2023.01.11
Javascript Koans  (0) 2023.01.04
원시 자료형과 참조 자료형  (0) 2023.01.02
계산기 구현하기  (1) 2023.01.01
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/06   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
글 보관함