localStorage 를 이용해서 로그인 / 회원가입 구현하기! (3) 수정, 추가 마지막 정리 편
gif 촬영이 조금 이상하게 됐지만 ... 원하던 기능을 구현하는 데에 성공! 했다.
js 코드 수정을 꽤 했는데 그래도 나름 이해했다고(?) 원하는대로 변경돼서 다행이었다.
완성한 걸 보니 허접하지만서도 뿌듯함을 감출 수가 없군 ~~ 다음에 만들 것도 열심히 만들어봐야겠다!!
완성한 코드 👇
<!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">
<title>로그인</title>
<link rel="stylesheet" href="css/style.css" />
</head>
<body>
<div class="main">
<div class="allBox">
<!--greeting-->
<div class="box">
<h1>로그인</h1>
</div>
<!--login form-->
<div class="box">
<form action="" id="loginForm">
<div class="box">
<input type="text" placeholder="아이디" id="idInput" autocomplete="off" />
</div>
<div class="box">
<input type="password" placeholder="비밀번호" id="pwInput" autocomplete="off" />
</div>
<div class="btnBox">
<button id="loginBtn">로그인</button>
</div>
<div class="box">
<span>
<a href="signup.html">회원가입</a>
</span>
</div>
</form>
</div>
</div>
</div>
<!--js load-->
<script type="text/javascript" src="js/login.js"></script>
</body>
</html>
index.html (login)
<!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="css/style.css" />
<title>회원가입</title>
</head>
<body>
<div class="main">
<div class="allBox">
<h1>회원가입</h1>
<form action="" id="signUpForm">
<div class="sufInput">
<label for="idInput">아이디</label>
<input type="text" id="idInput" placeholder="4자이상 10자이하" maxlength="10" minlength="4" autocomplete="off" required />
<span id="idCheckSpan"></span>
</div>
<div class="sufInput">
<label for="pwInput">비밀번호</label>
<input type="password" id="pwInput" placeholder="6자이상 10자이하" maxlength="10" minlength="6" autocomplete="off" required />
<span id="pwLengthSpan"></span>
</div>
<div class="sufInput">
<label for="pwCheckInput">비밀번호 확인</label>
<input type="password" id="pwCheckInput" placeholder="비밀번호를 똑같이 입력하세요!" maxlength="10" minlength="6" autocomplete="off" required />
<span id="pwCheckSpan"></span>
</div>
<div class="sufInput plusMargin">
<label for="nameInput">닉네임</label>
<input type="text" id="nameInput" placeholder="8자이하" maxlength="8" autocomplete="off" required />
</div>
<div class="sufInput plusMargin">
<label for="birthinput">생일(선택)</label>
<input type="date" id="birthInput" min="1920-01-01" />
</div>
<div class="btnBox">
<button id="signUpBtn">가입</button>
</div>
</form>
</div>
</div>
<!--js load-->
<script type="text/javascript" src="js/signup.js"></script>
<script>
const birth = document.querySelector("#birthInput");
const today = new Date();
const maxDay = `${today.getFullYear()}-${""+today.getMonth()+1}-${today.getDate()}`;
birth.setAttribute("max", maxDay);
console.log(maxDay);
</script>
</body>
</html>
signup.html
.hidden {
display: none;
}
html, body {
height: 100%;
margin: 0;
}
.main {
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
background: rgb(251,230,151);
background: radial-gradient(circle, rgb(255, 241, 191) 0%, rgb(156, 209, 105) 100%);
}
.main input {
padding: 8px;
margin: 5px 0;
width: 200px;
height: 20px;
}
.main input:focus {
outline: 2px solid rgb(156, 209, 105);
}
.main h1 {
margin: 20px 0;
}
.main a {
color: rgb(106, 106, 106);
font-size: 10pt;
text-decoration: none;
}
.main a:hover {
text-decoration: underline;
}
.allBox {
background-color: rgba(255, 251, 210, 0.8);
border: 1px solid rgb(255, 251, 210);
border-radius: 20px;
box-shadow: 0px 0px 8px rgb(255, 251, 210);
padding: 100px 80px;
}
.btnBox {
margin: 25px 0 15px 0;
}
.btnBox button {
padding: 10px 40px;
background-color: rgba(156, 209, 105, .5);
border: none;
border-radius: 5px;
margin: 10px 0;
}
.btnBox button:hover {
background-color: rgba(156, 209, 105, 1);
}
label {
display: block;
padding: 5px 0;
margin-top: 5px;
text-align: left;
font-size: 11pt;
}
.sufInput span {
display: block;
font-size: 10pt;
color: rgb(175, 37, 37);
padding: 10px;
}
.plusMargin {
margin-bottom: 20px;
}
style.css
const loginForm = document.querySelector("#loginForm");
function login(event) {
const idInput = document.querySelector("#idInput");
const pwInput = document.querySelector("#pwInput");
event.preventDefault();
const idValue = JSON.parse(localStorage.getItem("user"));
if (idValue != null && idValue.id === idInput.value) {
console.log(idValue.id);
if (idValue.pw === pwInput.value) {
// 로그인 성공하면 html 변신~
const mainString = document.querySelector("h1");
loginForm.classList.add("hidden");
mainString.innerText = `${idValue.name}님 환영합니다!`;
} else {
alert("비밀번호를 확인하세요");
pwInput.value = "";
}
} else if (idValue.id !== idInput.value) {
alert("없는 아이디입니다.");
idInput.value = "";
pwInput.value = "";
}
}
loginForm.addEventListener("submit", login);
login.js
const signUpForm = document.querySelector("#signUpForm");
const idInput = document.querySelector("#idInput");
const idCheckSpan = document.querySelector("#idCheckSpan");
const pwInput = document.querySelector("#pwInput");
const pwCheckInput = document.querySelector("#pwCheckInput");
const pwCheckSpan = document.querySelector("#pwCheckSpan");
const IDOK_KEY = "아이디를 사용하실 수 있습니다.";
const PWOK_KEY = "비밀번호가 확인되었습니다!";
// 아이디 중복체크
function idCheck() {
const ID_KEY = idInput.value;
const getId = localStorage.getItem("user");
const obj = JSON.parse(getId);
const engReg = /^[a-zA-Z0-9]/;
const etcReg = /[^a-zA-Z0-9]/gi;
if (
3 < ID_KEY.length &&
obj.id !== ID_KEY &&
engReg.test(ID_KEY) &&
!etcReg.test(ID_KEY)
) {
idCheckSpan.innerText = IDOK_KEY;
} else if (!engReg.test(ID_KEY) || etcReg.test(ID_KEY)) {
idCheckSpan.innerText = "영어와 숫자만 사용할 수 있어요.";
} else if (ID_KEY.length < 4) {
idCheckSpan.innerText = "아이디는 4글자 이상으로 정해주세요.";
} else if (obj.id === ID_KEY) {
idCheckSpan.innerText = "이미 있는 아이디예요";
}
}
// 비밀번호 중복체크
function pwCheck() {
if (pwInput.value === pwCheckInput.value) {
pwCheckSpan.innerText = PWOK_KEY;
} else pwCheckSpan.innerText = "비밀번호를 확인하세요";
// 비밀번호 수정하면 비밀번호 확인창 리셋
}
// 비밀번호 변경시 리셋
function resetFunc() {
pwCheckInput.value = "";
pwCheckSpan.innerText = "";
}
// 비밀번호 6자 이상인가욤
function pwLengthCheck() {
if (pwInput.value.length < 6) {
const pwLengthSpan = document.querySelector("#pwLengthSpan");
pwLengthSpan.innerText = "비밀번호는 6자 이상 입력해주세요.";
} else pwLengthSpan.innerText = "";
}
// 회원가입 정보 localStorage에 저장
function signUp(event) {
event.preventDefault();
const nameInput = document.querySelector("#nameInput");
const birthInput = document.querySelector("#birthInput");
let obj = {};
if (
pwCheckSpan.innerText === PWOK_KEY &&
idCheckSpan.innerText === IDOK_KEY
) {
obj.id = idInput.value;
obj.pw = pwInput.value;
obj.name = nameInput.value;
obj.birth = birthInput.value;
localStorage.setItem("user", JSON.stringify(obj));
alert("회원가입이 완료되었습니다!");
window.location.assign("index.html");
}
}
// Event Listner
idInput.addEventListener("keyup", idCheck);
pwCheckInput.addEventListener("keyup", pwCheck); // pw 똑같이 썼는지 체크
pwInput.addEventListener("keydown", resetFunc); // pw 수정시 비밀번호 확인, 확인문구 초기화
pwInput.addEventListener("keyup", pwLengthCheck);
signUpForm.addEventListener("submit", signUp);
signup.js
깨달은 점 / 추가하고 싶은 것들
1. html / css 에 서투르다.
내 생각보다 html, css 지식이나 사용법이(?) 더~ 서툴러서 애먹었다. 자료참고+공부의 필요성을 격하게 느꼈다.
2. 웹접근성에 대한 고민
웹접근성을 높이는 시맨틱한 코드 짜기는 정말 어렵구나. 어렵다고 표현했지만 거의 ... 완벽하게 접근성 낮은 웹페이지가 만들어진 것 같다 (ㅎ..) 내가 아직 html css를 정확히 이해하지 못해서 더더욱 그런거겠지. 여기도 공부가 필요해 ~ 다음에 만들 건 좀 더 html css가 (아마도)중요해질테니 공식문서를 열심히 읽어가며 만들어봐야겠다.
3. localStorage 잘못 알고 있던 지식 파악 후 수정
localStorage에서 Key 값을 가져올 수 있을 거라고 잘못 이해하고 있었어서 키값을 아이디값으로 할당했는데 ... 그럴 필요가 없다는 걸 깨달아서 전면 수정했다 !! 덕분에 다음에는 헷갈리지 않을 수 있을 것 같다.
4. 애니메이션을 추가하고 싶었다.
특히 로그인부분에서 비밀번호가 다를 때나 없는 아이디일 경우 input 창을 양옆으로 흔드는 애니메이션(?)을 만들고 싶었다.
근데 최근 스크린리더에 관심이 생겨서 ... 스크린리더로 애니메이션을 읽어낼 수 있을지에 대한 의문이 생겨서 일단은 추가하지 않았다.
이건 더 찾아봐야 할 것 같다. 내 검색 실력 문제인지 원하는 답이 안나온다 ㅠ_ㅠ.. 이 답을 찾아낸 다음에 나중에라도 애니메이션을 추가하고 싶다.