Skip to content
19 changes: 19 additions & 0 deletions assets/css/member.css
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,25 @@
color: var(--gray800);
}

.form__input-box .error-msg {
margin-top: var(--space-xxs);
padding: 0 var(--space-xs);
font-size: 14px;
}

/* validation 실패시 */
.form__input-box.isError .input {
border-color: var(--error);
}
.form__input-box.isError .error-msg {
color: var(--error);
}

/* validation 통과시 */
.form__input-box.isPass .input {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: isPass보다는 isValid 정도가 적당할것같네요!

border-color: var(--primary-color);
}

/* 비밀번호 인풋박스박스 */
.form__input-box-pw .input-box__input {
position: relative;
Expand Down
1 change: 1 addition & 0 deletions assets/css/variables.css
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
--gray700: #374151;
--gray800: #1f2937;
--gray900: #111827;
--error: #f74747;

/* space */
--space-xxs: 8px;
Expand Down
160 changes: 160 additions & 0 deletions assets/js/member.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
// 에러 메세지 생성 함수
const formEl = document.querySelector(".member-box__form");
const submitBtn = document.querySelector(".member-box__form .form__submitBtn");

const VALIDATION_RULE = {
nickname: {
noValue: {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: noValue => isEmpty 어떨까요?
복잡해보이는 네이밍을 기피하는것도 좋은 리팩토링이랍니다 :)

참고

msg: "닉네임을 입력해주세요.",
},
},
email: {
noValue: {
msg: "이메일을 입력해주세요.",
},
validation: {
pattern:
/^[0-9a-zA-Z]([-_\.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_\.]?[0-9a-zA-Z])*\.[a-zA-Z]{2,3}$/,
msg: "잘못된 이메일 형식입니다.",
},
},
password: {
noValue: {
msg: "비밀번호를 입력해주세요.",
},
validation: {
pattern: /^[0-9a-zA-Z]{8}/,
msg: "비밀번호를 8자 이상 입력해주세요.",
},
},
passwordConfirm: {
noValue: {
msg: "비밀번호를 입력해주세요.",
},
validation: {
msg: "비밀번호가 일치하지 않습니다.",
},
},
};

// 에러 메세지 생성
function createErrorMsg(text, inputBox) {
// 에러 메세지 중복 생성 방지
if (inputBox.querySelector(".error-msg")) return;

const msg = document.createElement("p");
msg.textContent = text;
msg.classList.add("error-msg");
inputBox.classList.add("isError");
inputBox.append(msg);
}

// input에 값 입력시 isError / isPass 초기화
function changeInputReset(e) {
const inputBox = e.target.closest(".form__input-box");

if (inputBox.classList.contains("isError")) {
inputBox.classList.remove("isError");
inputBox.querySelector(".error-msg").remove();
}

if (inputBox.classList.contains("isPass")) {
inputBox.classList.remove("isPass");
}
}

// 페이지내의 전체 input validation 통과했는지 확인
function checkAllPass() {
const inputs = document.querySelectorAll(".member-box__form .input");
const isAllPass = Array.from(inputs).every((input) =>
input.closest(".form__input-box").classList.contains("isPass")
);

submitBtn.disabled = !isAllPass;
}

// 항목별 validation 검사 :: 닉네임
function checkValidationNickname(value) {
if (value.length) return true;
return false;
}

// 항목별 validation 검사 :: 이메일
function checkValidationEmail(value) {
return VALIDATION_RULE.email.validation.pattern.test(value);
}

// 항목별 validation 검사 :: 패스워드
function checkValidationPassword(value) {
return VALIDATION_RULE.password.validation.pattern.test(value);
}

// 항목별 validation 검사 :: 패스워드 확인
function checkValidationPasswordConfirm(value) {
const password = document.querySelector("#password");
return password.value === value;
}

// validation 검사
function checkValidation({ target }) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당 함수는 비즈니스 로직과 UI가 불필요하게 결합되어있어 재사용이 불가하고, 하는일이 많아 복잡해보여요.
아래와 같이 분리해 단일 책임을 가질수있도록 리팩토링해볼까요?

  • 유효성 검사 (추후 재사용 가능한 단위로 함수 분리해 모듈화)
  • 이벤트 리스너 연결 및 UI 업데이트

if (!target.classList.contains("input")) return;
const targetValue = target.value;
const targetId = target.id;
const inputBox = target.closest(".form__input-box");
let isValidation;

// 값이 없는지 확인
if (!target.value.length) {
// 값이 없으면,
createErrorMsg(VALIDATION_RULE[targetId].noValue.msg, inputBox);
checkAllPass();
return;
}

// 항목별 validation 검사
switch (targetId) {
case "nickname":
isValidation = checkValidationNickname(targetValue);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

위에서 얘기했던 코멘트처럼 비즈니스 로직과 UI를 분리하게된다면 이렇게 checkValidation{Nickname} 과 같이 nickname, password, email에 해당하는 개별 함수들을 더이상 따로 만들지않아도 되겠죠? :)

break;
case "email":
isValidation = checkValidationEmail(targetValue);
break;
case "password":
isValidation = checkValidationPassword(targetValue);
break;
case "passwordConfirm":
isValidation = checkValidationPasswordConfirm(targetValue);
break;
}

if (!isValidation) {
// 항목별 validation 실패시
createErrorMsg(VALIDATION_RULE[targetId].validation.msg, inputBox);
} else {
// 항목별 validation 통과시
inputBox.classList.add("isPass");
}
checkAllPass();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이런 코드 흐름 너무 좋네요 👍 js에 대한 기본적인 이해도가 좋으신것같아요!

}

function togglePassword(e) {
if (!e.target.closest(".input-box__toggle")) return;
const pwBox = e.target.closest(".input-box__input");
const inputBox = pwBox.querySelector(".input");
if (pwBox.classList.contains("pw_show")) {
pwBox.classList.remove("pw_show");
inputBox.setAttribute("type", "password");
} else {
pwBox.classList.add("pw_show");
inputBox.setAttribute("type", "input");
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

classList.toggle을 사용하면 좀더 간결하게 만들어줄수있겠네요 :)
참고

function togglePassword(e) {
  if (!e.target.closest(".input-box__toggle")) return;
  const pwBox = e.target.closest(".input-box__input");
  const inputBox = pwBox.querySelector(".input");
  const isShow = pwBox.classList.toggle("pw_show");
  inputBox.setAttribute("type", isShow ? "text" : "password");
}


function movePage(e) {
location.href = e.target.dataset.moveLink;
}

formEl.addEventListener("input", changeInputReset);
formEl.addEventListener("focusout", checkValidation);
formEl.addEventListener("click", togglePassword);
submitBtn.addEventListener("click", movePage);
16 changes: 12 additions & 4 deletions login.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ <h1 class="logo">
</div>
</div>
<div class="form__input-box form__input-box-pw">
<label for="pw" class="input-box__label">비밀번호</label>
<label for="password" class="input-box__label">비밀번호</label>
<div class="input-box__input">
<input
type="password"
name="pw"
id="pw"
name="password"
id="password"
class="input"
placeholder="비밀번호를 입력해주세요."
/>
Expand All @@ -57,7 +57,14 @@ <h1 class="logo">
</button>
</div>
</div>
<button class="btn lg form__submitBtn">로그인</button>
<button
type="button"
class="btn lg form__submitBtn"
disabled
data-move-link="/items.html"
>
로그인
</button>
</form>
<!-- form :: E -->
<!-- sns-box :: S -->
Expand Down Expand Up @@ -100,5 +107,6 @@ <h2 class="sns-box__title">간편 로그인하기</h2>
</p>
</div>
</div>
<script src="./assets/js/member.js"></script>
</body>
</html>
24 changes: 16 additions & 8 deletions signup.html
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,12 @@ <h1 class="logo">
</div>
</div>
<div class="form__input-box form__input-box-pw">
<label for="pw" class="input-box__label">비밀번호</label>
<label for="password" class="input-box__label">비밀번호</label>
<div class="input-box__input">
<input
type="password"
name="pw"
id="pw"
name="password"
id="password"
class="input"
placeholder="비밀번호를 입력해주세요."
/>
Expand All @@ -69,14 +69,14 @@ <h1 class="logo">
</div>
</div>
<div class="form__input-box form__input-box-pw">
<label for="confirm_pw" class="input-box__label"
<label for="passwordConfirm" class="input-box__label"
>비밀번호 확인</label
>
<div class="input-box__input pw_show">
<div class="input-box__input">
<input
type="password"
name="confirm_pw"
id="confirm_pw"
name="passwordConfirm"
id="passwordConfirm"
class="input"
placeholder="비밀번호를 한번 더 입력해주세요."
/>
Expand All @@ -93,7 +93,14 @@ <h1 class="logo">
</button>
</div>
</div>
<button class="btn lg form__submitBtn">회원가입</button>
<button
type="button"
class="btn lg form__submitBtn"
disabled
data-move-link="/login.html"
>
회원가입
</button>
</form>
<!-- form :: E -->
<!-- sns-box :: S -->
Expand Down Expand Up @@ -136,5 +143,6 @@ <h2 class="sns-box__title">간편 로그인하기</h2>
</p>
</div>
</div>
<script src="./assets/js/member.js"></script>
</body>
</html>