[카테캠] FE week 9 (1)

werthers·2023년 6월 6일
0

카카오테크캠퍼스

목록 보기
10/16
post-thumbnail

회원가입 폼 만들기

  • Boilerplate 코드를 가져와 JS를 추가하여 기능을 구현한다.
  • 사전과제 요구사항에 맞춰 기능을 하나씩 만들어 본다.

주의사항 및 권장사항

  1. HTML 태그의 class, id는 수정하지 않고 그대로 사용합니다.
  2. 모든 DOM은 HTML에 명시된 id를 선택자로 사용해 가져옵니다.
  3. CSS 파일은 수정하지 않습니다.
  4. 기본적으로 정답은 index.js 파일에 작성하되, 다른 js 파일을 생성해 작성하는 것도 가능합니다.
  5. 기본 코드의 package.json에 명시된 라이브러리 외의 별도의 라이브러리 설치를 허용하지 않습니다.
  6. 함수를 기능 별로 분리해주세요.
  7. 일관성 있는 네이밍을 유지해주세요.
  8. 반복되는 기능은 하나로 통일해주세요.
  9. ES6(ES2015) 이후의 모던 자바스크립트 문법을 활용해주세요.

요구사항 기능 구현

1. autofocus

💡 `페이지가 로드 된 시점에 ID 입력 창에 Focus가 되어 있어야 합니다.`
  • ID 입력 input 태그에 페이지가 로드되었을 때 focus 이벤트를 발생시킨다.
  1. index.htmlinput id="id" 태그가 아이디 입력 태그임을 찾는다.
    1. const $idTag = document.getElementById('id')
  2. windowload 되는 이벤트 발생시 idTagfocus 를 준다.
    1. window.addEventListener('load', () => $idTag.focus)

2. 유효성 검사 로직

💡 ID, 비밀번호, 비밀번호 확인 필드에 대한 유효성 검사를 수행합니다.

유효성 검사 시점

  • input focus out 시 해당 input의 유효성을 검사합니다.
  • 가입하기 버튼을 눌렀을 때 모든 필드의 유효성을 검사합니다.

유효성 검사 패턴

모든 필드의 값은 빠짐 없이 입력해야 합니다.

ID, 비밀번호, 비밀번호 확인 필드는 유효성 조건을 충족해야 합니다.

  • ID: 5~20자. 영문 소문자, 숫자. 특수기호(_),(-)만 사용 가능
  • 비밀번호: 8~16자. 영문 대/소문자, 숫자 사용 가능
  • 비밀번호 확인: 비밀번호와 일치
  1. 각각 id, pw, pw-check 의 id 속성들을 가져온다.

  2. foucsout 이벤트 발생 시 유효성을 검사하는 함수를 각각 만든다.

    1. 유효성 검사를 위해 정규표현식 RegExp를 사용한다.
    2. const ID_REGEX = new RegExp(****^[a-z0-9_-]{5, 20}$)**
    3. const PW_REGEX = new RegExp(^[A-Za-z0-9]{8, 16}$)
    4. 각각의 유효성 검사를 이벤트리스너에 넘겨줄 수 있는 함수 형태로 만든다.
    5. focusout 이벤트 발생 시 함수를 넘겨주고, 가입하기 버튼 클릭 시에도 모든 유효성 검사를 실행한다.
    const validateId = (value) => {
        const isValidId = ID_REGEX.test(value)
        if (!isValidId)
    }
    
    const validatePw = (value) => {
      const isValidPw = PW_REGEX.test(value);
      if (!isValidPw)
    }
    
    const validatePwCheck = (value) => {
      const isValidPwCheck = $pw.value === value;
      if (!isValidPwCheck)
    }
    
    $idTag.addEventListener('focusout', validateId($idTag.value))
    $pw.addEventListener('focusout', validatePw($pw.value));
    $pwCheck.addEventListener('focusout', validatePwCheck($pwCheck.value));
    $submit.addEventListener('click', (event) => {
      event.preventDefault();
      validateId($idTag.value);
      validatePw($pw.value);
      validatePwCheck($pwCheck.value);
    })
  • 아직 유효하지 않은 값이 발생 시 에러 메시지 출력은 하지 않았다.

3. 커스텀 에러 메시지

💡 유효하지 않은 값일 경우, 각 경우에 맞는 에러 메시지를 보여주어야 합니다.

유효성 조건과 에러 메시지는 아래를 참고해주세요.

  • (공통) 빈 값일 경우: 필수 정보입니다.
  • [ID] 유효하지 않은 값일 경우: “5~20자의 영문 소문자, 숫자와 특수기호(_),(-)만 사용 가능합니다.”
  • [비밀번호] 유효하지 않은 값일 경우: “8~16자 영문 대 소문자, 숫자를 사용하세요.”
  • [비밀번호 확인] 유효하지 않은 값일 경우: “비밀번호가 일치하지 않습니다.”
  1. 각각 id-msg pw-msg pw-check-msg id 속성을 가져온다.
  2. focusoutclick 이벤트(submit)에서 유효하지 않은 값일 경우 에러 메시지를 추가하며 border-red-600 class 추가
const ID_ERROR_MSG = {
  required: '필수 정보입니다.',
  invalid: '5~20자의 영문 소문자, 숫자와 특수기호(_),(-)만 사용 가능합니다.',
};

const validateId = (value) => {
    let isValidId;
    if (value.length === 0)
      isValidId = 'required';
    isValidId = (ID_REGEX.test(value) ? true : 'invalid');
    if (isValidId !== true)
    {
      $idTag.classList.add('border-red-600');
      $idMsg.innerText = ID_ERROR_MSG[isValidId];
    } else {
      $idTag.classList.remove('border-red-600');
      $idMsg.innerText = '';
    }
}
  1. pw pwCheck 도 비슷한 로직으로 에러 메시지를 변경하여 추가한다.

4. 입력 확인 모달 창

💡 **제출하기** 버튼 클릭 시, **모든 input의 값이 유효한 상태일 경우** 입력한 아이디와 비밀번호를 확인할 수 있는 모달 창을 보여주어야 합니다.
  • dialog : 대화 상자 (상호 작용) DOM을 이용하여 모달 창을 제어한다.
  • dialog.showModal() : 대화 상자에 적용된 css를 포함하여 모달을 open한다.
  • dialog.close() : 대화 상자를 닫는다.
  1. html의 dialog DOM을 찾고 submit 버튼을 클릭한 후 유효성 검사 완료하고 모달을 오픈하도록 한다.
    1. const modal = document.getElementById('modal');
  2. submit의 이벤트 리스너에서 유효성 검사를 마친 뒤 그 값이 모두 true라면 confirmId/pw 값에 각각 id와 pw 값을 입력해주고 modal을 오픈해준다.
  3. approve/cancelBtn 들이 각각 click 이벤트 발생 시 가입 알림 혹은 modal.close() 를 해준다.
$submit.addEventListener('click', (event) => {
    event.preventDefault()
    const isValidForm =
        validateId($idTag.value) === true &&
        validatePw($pw.value) === true &&
        validatePwCheck($pwCheck.value) === true
    if (isValidForm) {
        $confirmId.innerText = $idTag.value
        $confirmPw.innerText = $pw.value
        $modal.showModal()
    }
})

$cancelBtn.addEventListener('click', () => {
    $modal.close()
})

$approveBtn.addEventListener('click', () => {
    window.alert('가입되었습니다.')
    $modal.close()
})

5. 폰트 사이즈 조절 버튼

💡 회원가입 폼에 사용된 기본 폰트 사이즈는 **16px**입니다.

기본 폰트 사이즈를 기준으로 1px씩 폰트 사이즈를 조절할 수 있는 기능을 구현해주세요.

(최소: 12px, 최대: 20px)

  • 현재 폰트 사이즈가 20px일 경우 + 버튼 비활성화
  • 현재 폰트 사이즈가 12px일 경우 `` 버튼 비활성화
  1. + - 버튼에 해당하는 DOM을 가져온다.

  2. 버튼에 click 이벤트 발생 시 font-size를 조절한다.

  3. 회원가입 폼 모든 요소의 font-size를 조절할 수 있는 DOM (html)을 찾는다.

    1. document.documentElementhtml 요소를 가져온다.
    2. rem 단위 : 상대 길이 단위로 루트 요소(html)의 글꼴 크기에 따라 크기를 조절한다.
    3. 이 때 console에서 inline으로 작성하지 않은 style에 대해 가져올 수 없기 때문에 Window.getComputedStyle() 메소드를 사용하여 폰트 사이즈를 확인할 수 있다.
    4. increase, decrease의 로직이 비슷하기 떄문에 하나의 메소드에서 처리하도록 하고 flag 매개변수를 통해 기능을 다르게 하는 방식으로 구현한다.
    $increaseFontBtn.addEventListener('click', () => {
        onClickFontSizeControl('increase')
    })
    
    $decreaseFontBtn.addEventListener('click', () => {
        onClickFontSizeControl('decrease')
    })
    
    const onClickFontSizeControl = (flag) => {
        const fontSize = $getHtmlFontSize()
        let newFontSize = flag === 'increase' ? fontSize + 1 : fontSize - 1
        $html.style.fontSize = newFontSize
        $decreaseFontBtn.disabled = newFontSize <= MIN_FONT_SIZE
        $increaseFontBtn.disabled = newFontSize >= MAX_FONT_SIZE
    }

6. 리팩토링

  • 비슷한 역할을 하는 코드들을 하나로 합쳐 간결하게 코드를 작성한다.
  1. id pw pwCheck 의 유효성 검사하는 함수의 유사 기능을 하나의 함수로 재구현한다.

    // 3개의 비슷한 기능을 하는 함수 찾기
    const ID_ERROR_MSG = {
        required: '필수 정보입니다.',
        invalid: '5~20자의 영문 소문자, 숫자와 특수기호(_),(-)만 사용 가능합니다.',
    }
    
    const PW_ERROR_MSG = {
        required: '필수 정보입니다.',
        invalid: '8~16자 영문 대 소문자, 숫자를 사용하세요.',
    }
    
    const PW_CHECK_ERROR_MSG = {
        required: '필수 정보입니다.',
        invalid: '비밀번호가 일치하지 않습니다',
    }
    
    const checkIdRegex = (value) => {
        if (value.length === 0) return 'required'
        return ID_REGEX.test(value) ? true : 'invalid'
    }
    
    const checkPwRegex = (value) => {
        if (value.length === 0) return 'required'
        return PW_REGEX.test(value) ? true : 'invalid'
    }
    
    const checkPwCheckRegex = (value) => {
        if (value.length === 0) return 'required'
        else {
            return  $pw.value === value ? true : 'invalid'
        }
    }
    //리팩토링 후
    const ERROR_MSG = {
        require: '필수 정보입니다.',
        invalidId:
            '5~20자의 영문 소문자, 숫자와 특수기호(_),(-)만 사용 가능합니다.',
        invalidPw: '8~16자 영문 대 소문자, 숫자를 사용하세요.',
        invalidPwCheck: '비밀번호가 일치하지 않습니다.',
    }
    const checkRegex = (value, id) => {
        if (value.length === 0) return 'required' //공통된 로직
        switch (id) {
            case 'id':
                return ID_REGEX.test(value) ? true : 'invalidId'
            case 'pw':
                return PW_REGEX.test(value) ? true : 'invalidPw'
            case 'pw-check':
                return $pw.value === value ? true : 'invalidPwCheck'
        }
    }
  2. 각각 유효성 검사 후 에러 메시지를 출력하는 부분도 유사한 기능을 하나의 메소드로 재구현한다.

//리팩토링 전
const validateId = (value) => {
    let isValidId = checkRegex(value, 'id')
    if (isValidId !== true) {
        $idTag.classList.add('border-red-600')
        $idMsg.innerText = ERROR_MSG[isValidId]
    } else {
        $idTag.classList.remove('border-red-600')
        $idMsg.innerText = ''
    }
    return isValidId
}
const validatePw = (value) => {
    let isValidPw = checkRegex(value, 'pw')
    if (isValidPw !== true) {
        $pw.classList.add('border-red-600')
        $pwMsg.innerText = ERROR_MSG[isValidPw]
    } else {
        $pw.classList.remove('border-red-600')
        $pwMsg.innerText = ''
    }
    return isValidPw
}
const validatePwCheck = (value) => {
    let isValidPwCheck = checkRegex(value, 'pw-check')
    if (isValidPwCheck !== true) {
        $pwCheck.classList('border-red-600')
        $pwCheckMsg.innerText = ERROR_MSG[isValidPwCheck]
    }
    return isValidPwCheck
}
//리팩토링 후
const checkValidation = (target, msgTarget) => {
    const isValid = checkRegex(target)
    if (isValid !== true) {
        target.classList.add('border-red-600')
        msgTarget.innerText = ERROR_MSG[isValid]
    } else {
        target.classList.remove('border-red-600')
        msgTarget.innerText = ''
    }
    return isValid
}
profile
Hello World !

0개의 댓글