으쌰으쌰

localStorage 를 이용해서 로그인 / 회원가입 구현하기! (3) 수정, 추가 마지막 정리 편

HYEMBURGER 2023. 1. 21. 18:42

 

GIT🧑‍💻

 

회원가입 완성!
로그인 완성!

 

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 창을 양옆으로 흔드는 애니메이션(?)을 만들고 싶었다.

근데 최근 스크린리더에 관심이 생겨서 ... 스크린리더로 애니메이션을 읽어낼 수 있을지에 대한 의문이 생겨서 일단은 추가하지 않았다.

이건 더 찾아봐야 할 것 같다. 내 검색 실력 문제인지 원하는 답이 안나온다 ㅠ_ㅠ.. 이 답을 찾아낸 다음에 나중에라도 애니메이션을 추가하고 싶다.