[JavaScript/브라우저] 회원가입 유효성검사 만들기

KIM DA MI·2023년 3월 8일
10

JS/브라우저

목록 보기
2/2
post-thumbnail
  • 누구나 한 번쯤은 웹사이트의 회원가입을 진행해 보신 경험이 있을 것이다.
    가입 과정을 거치다 보면, 사이트에서 원하는 조건에 맞게 반드시 형식을 맞춰 입력해야 하는 경우가 생긴다.
    • 필수로 입력해야 하는 항목
      • 아이디, 이메일, 비밀번호, 이름, 전화번호 등
    • 입력 조건
      • 비밀번호는 n 자릿수 이상이어야 하고, 숫자나 특수문자를 반드시 포함해야 한다.
      • 비밀번호와 비밀번호 확인란에 입력된 문자가 동일해야 합니다.
      • 신용카드의 경우, 입력한 신용카드의 번호가 유효해야 합니다.

  • 이런 기능을 유효성 검사(Form validation)라고 부른다.
    유효성 검사는 실제 개발 과정에서 많이 맞닥뜨리는 문제 중 하나이다.

  • 회원가입처럼 작은 기능 단위의 제품을 만들기 위해서는, 위와 같이 요구 사항을 정리하는 과정이 매우 중요하다.
  • 유효성 검사의 목표는 회원 가입이라는 핵심 기능에 대해, 작동이 가능한 MVP(Minimum Viable Product)를 만들어 내는 것이다.


    지난 시간 배웠던 DOM을 활용하여 회원가입 유효성 검사를 구현해보자.



🟠 HTML


1. 회원가입 항목 조건

  • 아이디 : 4~12글자, 영어나 숫자만 가능하다.
  • 비밀번호 : 8글자 이상, 영문, 숫자, 특수문자를 모두 사용해야 한다.
  • 비밀번호 확인 : 비밀번호와 일치해야 한다.

2. HTML 구조 설계하기


3. HTML 작성

<body>
  <main>
    <img
         class="logo"
         src="./images/codestates-logo1.png"
         alt="CODE_STATES_LOGO"
         />

    <fieldset>
      <input type="text" id="username" placeholder="아이디" />
    </fieldset>

    <div class="success-message hide">사용할 수 있는 아이디입니다</div>
    <div class="failure-message hide">아이디는 4~12글자이어야 합니다</div>
    <div class="failure-message2 hide">영어 또는 숫자만 가능합니다</div>

    <fieldset>
      <input type="password" id="password" placeholder="비밀번호" />
    </fieldset>

    <div class="strongPassword-message hide">8글자 이상, 영문, 숫자, 특수문자(@$!%*#?&)를 사용하세요</div>

    <fieldset>
      <input
             type="password"
             id="password-retype"
             placeholder="비밀번호 확인"
             />
    </fieldset>

    <div class="mismatch-message hide">비밀번호가 일치하지 않습니다</div>

    <fieldset class="signup">
      <button>회원가입</button>
    </fieldset>

    <script src="script2.js"></script>
  </main>
</body>
  • HTML <fieldset> 요소는 웹 양식의 여러 컨트롤과 레이블(<label>)을 묶을 때 사용한다.

4. HTML 브라우저 확인



🟡 JavaScript


  • 이제 javaScript를 이용하여 DOM으로 HTML을 조작해보자!

1. 엘리먼트 정보 가져오기

  • document.querySelector를 이용해 엘리먼트 정보를 가져온다.

1-1. 아이디 정보 가져오기

// 1. 아이디 입력창 정보 가져오기
let elInputUsername = document.querySelector('#username'); // input#username
// 2. 성공 메시지 정보 가져오기
let elSuccessMessage = document.querySelector('.success-message'); // div.success-message.hide
// 3. 실패 메시지 정보 가져오기 (글자수 제한 4~12글자)
let elFailureMessage = document.querySelector('.failure-message'); // div.failure-message.hide
// 4. 실패 메시지2 정보 가져오기 (영어 또는 숫자)
let elFailureMessageTwo = document.querySelector('.failure-message2'); // div.failure-message2.hide

1-2. 비밀번호 정보 가져오기

// 1. 비밀번호 입력창 정보 가져오기
let elInputPassword = document.querySelector('#password'); // input#password
// 2. 비밀번호 확인 입력창 정보 가져오기
let elInputPasswordRetype = document.querySelector('#password-retype'); // input#password-retype
// 3. 실패 메시지 정보 가져오기 (비밀번호 불일치)
let elMismatchMessage = document.querySelector('.mismatch-message'); // div.mismatch-message.hide
// 4. 실패 메시지 정보 가져오기 (8글자 이상, 영문, 숫자, 특수문자 미사용)
let elStrongPasswordMessage = document.querySelector('.strongPassword-message'); // div.strongPassword-message.hide



2. 유효성 검증 함수 작성하기

2-1. 아이디 : 글자 수 제한 (4글자 이상, 12글자 이하)

function idLength(value) {
  return value.length >= 4 && value.length <= 12
}
  • 4글자 이상 또는 12글자 이하인 경우 true, 아니면 false를 리턴한다.

2-2. 아이디 : 영어 또는 숫자만 가능


function onlyNumberAndEnglish(str) {
  return /^[A-Za-z0-9][A-Za-z0-9]*$/.test(str);
}
  • 영어 또는 숫자가 들어간 경우 true, 아니면 false를 리턴한다.
    • test() : 문자열에 일치하는 부분이 있는지 확인한다. true 또는 false를 반환

2-3. 비밀번호 : 8글자 이상, 영문, 숫자, 특수문자 사용

function strongPassword (str) {
  return /^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!%*#?&]{8,}$/.test(str);
}
  • 최소 8글자 이상이면서, 알파벳과 숫자 및 특수문자(@$!%*#?&)가 하나 이상 포함될 경우 true, 아니면 false를 리턴한다.

2-4. 비밀번호 확인 : 비밀번호와 비밀번호 확인 일치

function isMatch (password1, password2) {
  return password1 === password2;
}
  • 비밀번호와 비밀번호 확인이 일치할 경우 true, 아니면 false를 리턴한다.



3. 이벤트 핸들러

  • 이벤트 핸들러 함수로 이벤트가 발생했을 때 유효성 검사를 실행해보자.

+ CSS

  • 먼저 클래스별로 hide라는 클래스를 추가하여 CSS 속성으로 display: none을 추가한다.
  • 해당 hide 클래스가 존재하는 경우 화면에 엘리먼트가 표시되지 않는다.
  • 이 속성으로 유효성 검사의 요구사항이 부적합할 때만 시각적 피드백을 제공할 수 있다.
    .hide {
    display: none;
    }

3-1. 아이디 이벤트 (4글자 이상 12글자 이하, 영어 또는 숫자만 가능)

  • onkeyup : 키보드가 눌렸다 떼어졌을 때를 의미

  • elInputUsername이 키보드로 입력이 됐을 때 이벤트 핸들러 안에 있는 내용이 실행된다.

    elInputUsername.onkeyup = function () {
      // 값을 입력한 경우
      if (elInputUsername.value.length !== 0) {
        // 영어 또는 숫자 외의 값을 입력했을 경우
        if(onlyNumberAndEnglish(elInputUsername.value) === false) {
          elSuccessMessage.classList.add('hide');
          elFailureMessage.classList.add('hide');
          elFailureMessageTwo.classList.remove('hide'); // 영어 또는 숫자만 가능합니다
        }
        // 글자 수가 4~12글자가 아닐 경우
        else if(idLength(elInputUsername.value) === false) {
          elSuccessMessage.classList.add('hide'); // 성공 메시지가 가려져야 함
          elFailureMessage.classList.remove('hide'); // 아이디는 4~12글자이어야 합니다
          elFailureMessageTwo.classList.add('hide'); // 실패 메시지2가 가려져야 함
        }
        // 조건을 모두 만족할 경우
        else if(idLength(elInputUsername.value) || onlyNumberAndEnglish(elInputUsername.value)) {
          elSuccessMessage.classList.remove('hide'); // 사용할 수 있는 아이디입니다
          elFailureMessage.classList.add('hide'); // 실패 메시지가 가려져야 함
          elFailureMessageTwo.classList.add('hide'); // 실패 메시지2가 가려져야 함
        }
      }
      // 값을 입력하지 않은 경우 (지웠을 때)
      // 모든 메시지를 가린다.
      else {
        elSuccessMessage.classList.add('hide');
        elFailureMessage.classList.add('hide');
        elFailureMessageTwo.classList.add('hide');
      }
    }
    • 조건이 부적합할 경우 : .classList.remove('hide')hide 클래스를 삭제하여 화면에 표시한다.
    • 조건이 적합할 경우 : .classList.add('hide')hide 클래스를 추가하여 화면에서 가린다.

3-2. 비밀번호 이벤트 (8글자 이상, 영문, 숫자, 특수문자 사용)

  • onkeyup : 키보드가 눌렸다 떼어졌을 때를 의미

  • elInputPassword이 키보드로 입력이 됐을 때 이벤트 핸들러 안에 있는 내용이 실행된다.

    elInputPassword.onkeyup = function () {
    
      // console.log(elInputPassword.value);
      // 값을 입력한 경우
      if (elInputPassword.value.length !== 0) {
        if(strongPassword(elInputPassword.value)) {
          elStrongPasswordMessage.classList.add('hide'); // 실패 메시지가 가려져야 함
        }
        else {
          elStrongPasswordMessage.classList.remove('hide'); // 실패 메시지가 보여야 함
        }
      }
      // 값을 입력하지 않은 경우 (지웠을 때)
      // 모든 메시지를 가린다.
      else {
        elStrongPasswordMessage.classList.add('hide');
      }
    };
    • 조건이 부적합할 경우 : .classList.remove('hide')hide 클래스를 삭제하여 화면에 표시한다.
    • 조건이 적합할 경우 : .classList.add('hide')hide 클래스를 추가하여 화면에서 가린다.

3-3. 비밀번호 확인 이벤트 (비밀번호와 비밀번호 확인 일치)

  • onkeyup : 키보드가 눌렸다 떼어졌을 때를 의미

  • elInputPasswordRetype이 키보드로 입력이 됐을 때 이벤트 핸들러 안에 있는 내용이 실행된다.

    elInputPasswordRetype.onkeyup = function () {
    
      // console.log(elInputPasswordRetype.value);
      if (elInputPasswordRetype.value.length !== 0) {
        if(isMatch(elInputPassword.value, elInputPasswordRetype.value)) {
          elMismatchMessage.classList.add('hide'); // 실패 메시지가 가려져야 함
        }
        else {
          elMismatchMessage.classList.remove('hide'); // 실패 메시지가 보여야 함
        }
      }
      else {
        elMismatchMessage.classList.add('hide'); // 실패 메시지가 가려져야 함
      }
    };
    • 조건이 부적합할 경우 : .classList.remove('hide')hide 클래스를 삭제하여 화면에 표시한다.
    • 조건이 적합할 경우 : .classList.add('hide')hide 클래스를 추가하여 화면에서 가린다.



🔵 CSS


1. 디자인 구상하기

  • 오늘은 글래스모피즘 디자인을 구현해보고 싶었다.
    • 글래스모피즘(glassmorphism)이란? : 반투명 재질을 사용하여 오브젝트 간의 시각적 계층을 표현한 그래픽 스타일
  • 자료를 찾아보니 글래스모피즘 디자인을 CSS 코드로 바꿔주는 사이트가 있어 참고하였다.
  • 글래스모피즘 참고 사이트 : css.glass

  • 배경은 무료 이미지 사이트인 pixabay에서 이미지를 다운받았다.
    • 배경으로 쓸 것이기 때문에 가장 고화질로 다운 받았다.



2. 디자인 레이아웃 잡기

  • 먼저 스타일을 적용하기 전 레이아웃을 먼저 잡는다.
  • 아까 설계했던 그림을 참고하여 레이아웃을 그린다.


레이아웃 그린 모습

  • 스타일을 적용하기 전 틀(외곽선)을 잡을 때, 영역별로 색깔을 다르게 표시해주는 편이다.
    이렇게 미리 표시해두면 꾸밀 때 어떤 영역에 해당하는 부분인지 구분하기 더 쉽다.
  1. 기본 스타일링을 제거
    *{
      box-sizing: border-box;
      padding: 0;
      margin: 0;
      font-family: 'Spoqa Han Sans Neo', 'sans-serif';
      /* font-size: 16px; */
    }

  2. 배경 영역
    body {
      border: 1px solid red;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      width: 100vw;
      height: 100vh;
    }

  3. 회원가입 틀 영역
    main {
      border: 1px solid red;
      display: flex;
      flex-direction: column;
      align-items: center;
      width: 23rem;
      height: auto;
      padding: 30px;
    }

  4. 로고 영역
    .logo {
      border: 1px solid blue;
      width: 170px;
      margin: 12px auto 30px;
    }

  5. 입력칸 틀 영역
    fieldset {
      border: 1px solid green;
      display: flex;
      flex-direction: column;
      justify-content: center;
      margin: 10px;
      padding: 10px 12px;
    }

  6. 입력칸 영역
    input {
      border: 1px solid purple;
      width: 15rem;
    }

  7. 회원가입 버튼
    button {
      border: 1px solid purple;
      cursor: pointer;
      width: 16.3rem;
      height: 3rem;
    }



3. 스타일 적용하기

1. 배경 스타일 적용하기

body {
  background-image: url('./images/beach.jpg');
  background-size: cover;
  background-repeat: no-repeat;
}


2. 회원가입 틀 영역 스타일 적용하기

  • 글래스모피즘을 사용할 때 계속 디자인이 연출되는 것보다는 hover 했을 때만 글래스 효과가 나타나게 하고 싶었다.
  • 그래서 hover 전에는 투명하게 연출하여 배경에 좀 더 시선이 머물도록 하였다.
  • hover 하기 전
    main {
      background: linear-gradient(124.47deg, 
                  rgba(255, 255, 255, 0.0), 
                  rgba(255, 255, 255, 0.0), 
                  rgba(255, 255, 255, 0.0)); /* 배경색이 투명하게 보이게 한다 */
      border-radius: 16px;
      box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);
      backdrop-filter: blur(0px);
    }
  • hover 했을 때 (커서(마우스 포인터)가 요소 위에 올라가 있을 때)
    main:hover {
      background: linear-gradient(124.47deg, 
                rgba(255, 255, 255, 0.2), 
                rgba(255, 255, 255, 0.0), 
                rgba(255, 255, 255, 0.2));
      border-radius: 16px;
      box-shadow: 0 4px 30px rgba(0, 0, 0, 0.3);
      backdrop-filter: blur(5px);
    }

3. 로고 영역 스타일 적용하기

  • 로고를 그대로 사용하기에는 매치가 잘 되지 않아 어울리도록 하얀색으로 바꿔주었다! (포토샵 사용)
  • 바꾼 로고를 적용한 모습 (hover 상태에 캡쳐)

4. 입력칸 틀 영역

  • 전체 스타일과 어울리게 테두리를 둥글게 만들어 준다. (초록색)
    fieldset {
      border-radius: 50px;

  • 입력 영역회원가입 영역 스타일을 다르게 주기 위해 :not() 선택자 :last-of-type 가상선택자를 사용한다.
    • :not()은 인수로 표시되지 않은 요소와 일치한다.
    • :last-of-type : 요소 그룹 중에서 해당 유형의 마지막 요소를 나타낸다.
  • hover 하기 전
    fieldset:not(:last-of-type){
      background: linear-gradient(124.47deg, 
                rgba(255, 255, 255, 0.2), 
                rgba(255, 255, 255, 0.0), 
                rgba(255, 255, 255, 0.2));
      box-shadow: 0 4px 30px rgba(0, 0, 0, 0.2);
      backdrop-filter: blur(0px);
      -webkit-backdrop-filter: blur(0px);
      border: 1px solid rgba(255, 255, 255, 0.3);
    }


  • hover 했을 때 (아이디 영역에 커서를 올림)
    fieldset:not(:last-of-type):hover{
      background: linear-gradient(124.47deg, 
                rgba(255, 255, 255, 0.5), 
                rgba(255, 255, 255, 0.3), 
                rgba(255, 255, 255, 0.5));
      box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);
      backdrop-filter: blur(5px);
      -webkit-backdrop-filter: blur(5px);
      border: 1px solid rgba(255, 255, 255, 0.3);
    }

5. 입력칸 영역

  • <input> 태그에는 외곽선을 따로 설정하지 않아도 기본으로 나타나기 때문에 border: none로 안보이게 설정했다.
  • 입력칸 틀에 이미 스타일을 적용했기 때문에 background-color:transparent로 입력칸 배경을 투명하게 만들어준다.
    input {
      border: none;
      background-color:transparent;
      font-size: 16px;
      color: rgba(255, 255, 255, 0.9);
    }
  • color: rgba(255, 255, 255, 0.9) 글자색을 적용했음에도 왜 그대로일까?
  • 적용된 글자색은 입력했을 때의 글자이다.
  • 도움말에 있는 글자색을 적용하기 위해 ::placeholder를 활용한다.
    input::placeholder {
      color: rgb(255, 255, 255, 0.5);
    }
  • input 박스를 클릭했을 때 보이는 외곽선을 지우기 위해 ::focus를 활용해 outlinenone으로 설정한다.
    input:focus {
      outline: none;
    }


6. 회원가입 버튼 영역

  • border: none;.signup영역의 외곽선을 안보이게 설정하였다.
    .signup {
      border: none;
    }

  • 회원가입 버튼에도 스타일을 적용한다.
  • hover
    button {
      border: 1px solid rgba(255, 255, 255, 0.3);
      border-radius: 50px;
      color: rgba(255, 255, 255, 0.9);
      font-size: 16px;
      box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);
      background: linear-gradient(124.47deg, 
                rgba(61, 151, 215, 0.2), 
                rgba(61, 151, 215, 0.0), 
                rgba(61, 151, 215, 0.2));
      backdrop-filter: blur(5px);
    }

  • hover 했을 때
    button:hover {
      background: linear-gradient(124.47deg, 
                rgba(61, 151, 215, 0.8), 
                rgba(61, 151, 215, 0.6), 
                rgba(61, 151, 215, 0.8));
      top: 1px;
      margin-top: 1px;
    }

  • active 상태일 때 (버튼을 눌렀을 때)
    button:active {
      position: relative;
      top: 5px;
      margin-top: 5px;
    }

7. 실패 메시지 영역

  • 유효성 검사에 적합하지 않는 경우 발생하는 실패 메시지에도 스타일을 적용한다.
    main > div {
      color: #ffffff;
      font-size: 14px;
      padding: 0px 30px 0px 30px;
    }



4. 완성


1개의 댓글

comment-user-thumbnail
2023년 3월 17일

글쓰는 방법부터 내용까지 잘 읽었습니다 :)

답글 달기