Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
/>
<meta
property="og:image"
content="https://www.google.com/imgres?q=%ED%8C%90%EB%8B%A4&imgurl=https%3A%2F%2Fi.namu.wiki%2Fi%2FN7XtnLu7mENPBU1wMlAoOo5_w13roksendvuswR8gkFw_8SilcxCpT3kTTdzaP42jSpZAQ2-R4x3aNxaj6A3JA.webp&imgrefurl=https%3A%2F%2Fnamu.wiki%2Fw%2F%25ED%258C%2590%25EB%258B%25A4&docid=5YXeSdnyXQW-OM&tbnid=L95TdOcl4sN4TM&vet=12ahUKEwiptZXLvcyMAxU7sVYBHUTEITMQM3oECG4QAA..i&w=578&h=385&hcb=2&ved=2ahUKEwiptZXLvcyMAxU7sVYBHUTEITMQM3oECG4QAA"
content="https://i.namu.wiki/i/gPk17m9bSWihfGnpoCK_GkWdYAQMnDwbcTDKOAWmZ6jfSzvJJnVJRNmAovYNXgd0ElvPmYkj90EAek4L63N4gk0fg2GEQqBbnSw9v52fvn0vXBGF1z8ZGOgKRC1ybx9QJXdYaDzkK9MB5a_aLdjXh_AvSGFUrI3eGd4HFCMSOqQ.webp"
/>
<meta
property="og:url"
Expand Down Expand Up @@ -68,8 +68,8 @@ <h2>일상의 모든 물건을 거래해 보세요</h2>
alt="home-card01"
/>
<div class="section-home-text">
<h1>Hot item</h1>
<h2>인기 상품을 <br />확인해 보세요</h2>
<span class="blue">Hot item</span>
<span>인기 상품을 <br />확인해 보세요</span>
<p>
가장 HOT한 중고거래 물품을<br />
판다 마켓에서 확인해 보세요
Expand All @@ -82,11 +82,11 @@ <h2>인기 상품을 <br />확인해 보세요</h2>
alt="home-card02"
/>
<div class="section-home-text reverse">
<h1>Search</h1>
<h2>
<span class="blue">Search</span>
<span>
구매를 원하는 <br />
상품을 검색하세요
</h2>
</span>
<p>
구매하고 싶은 물품은 검색해서 <br />
쉽게 찾아보세요
Expand All @@ -99,8 +99,8 @@ <h2>
alt="home-card03"
/>
<div class="section-home-text">
<h1>Register</h1>
<h2>판매를 원하는 <br />상품을 등록하세요</h2>
<span class="blue">Register</span>
<span>판매를 원하는 <br />상품을 등록하세요</span>
<p>
어떤 물건이든 판매하고 싶은 상품을 <br />
쉽게 등록하세요
Expand Down
9 changes: 7 additions & 2 deletions login.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
<link rel="stylesheet" href="./styles/components/sign.css" />
<link rel="stylesheet" href="./styles/components/buttons.css" />
<link rel="stylesheet" href="./styles/components/footer.css" />

<!-- script -->
<script src="./login.js"></script>
Copy link
Collaborator

Choose a reason for hiding this comment

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

signup.html 과 login.html에 같은 컴포넌트가 있어 동시 적용하려고 sign.js 하나의 파일에 작성하려고 했으나 잘 동작이 안되서 따로 만들었습니다. 혹시 같은 컴포넌트를 작성하고 임포트 하는 방법이 있나요?
-> 바닐라 자바스크립트에서 import를 쓰실려면 <script type="module" src="./login.js"></script> 로 써주시거나 리엑트 쓰실 때 처럼 웹팩같은 번들러를 활용하셔야 합니다 :)
https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/Modules

<script src="togglePasswordBtn.js"></script>
</head>
<body>
<div class="login-container">
Expand All @@ -32,6 +36,7 @@
name="email"
placeholder="이메일을 입력해 주세요"
/>
<span class="error-message" id="email-error"></span>
</div>
<div class="input-item">
<label for="password">비밀번호</label>
Expand All @@ -42,14 +47,14 @@
name="password"
placeholder="비밀번호를 입력해 주세요"
/>
<button>
<button type="button" class="toggle-password-btn">
<img
src="styles/assets/icons/icon/eyes_off.svg"
alt="toggle-password"
class="toggle-password"
/>
</button>
</div>
<span class="error-message" id="password-error"></span> </span>
</div>
<button type="submit" class="btn-large full-width">
로그인
Expand Down
88 changes: 88 additions & 0 deletions login.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
document.addEventListener("DOMContentLoaded", () => {
const emailInput = document.getElementById("email");
Copy link
Collaborator

Choose a reason for hiding this comment

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

변수명이 명확합니다! 👍

const passwordInput = document.getElementById("password");
const emailError = document.getElementById("email-error");
const passwordError = document.getElementById("password-error");
const form = document.querySelector(".login-form");
const submitBtn = document.querySelector(".btn-large");

submitBtn.disabled = true; // 초기 상태에서 버튼 비활성화
Copy link
Collaborator

Choose a reason for hiding this comment

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

html 속성을 이용하실 수 있습니다~!

<button disabled>로그인</button>


// 필드별로 touched 상태를 추적
let emailTouched = false;
let passwordTouched = false;

// 유효성 검사 함수
function validateEmail() {
if (!emailTouched) return true;
const emailValue = emailInput.value.trim();
if (!emailValue) {
emailError.textContent = "이메일을 입력해 주세요.";
Copy link
Collaborator

Choose a reason for hiding this comment

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

에러 UI 관련 부분이 반복되고 있네요! 이런 경우 함수로 묶어 주시면 유지보수, 가독성에 도움이 됩니다 :)

emailInput.classList.add("error");
return false;
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(emailValue)) {
emailError.textContent = "잘못된 이메일입니다.";
emailInput.classList.add("error");
return false;
}
emailError.textContent = ""; // 에러 메시지 초기화
Copy link
Collaborator

Choose a reason for hiding this comment

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

에러 제거 또한 함수로 정의할 수 있겠죠!

emailInput.classList.remove("error");
return true;
}

function validatePassword() {
if (!passwordTouched) return true;
const passwordValue = passwordInput.value.trim();
if (!passwordValue) {
passwordError.textContent = "비밀번호를 입력해 주세요.";
passwordInput.classList.add("error");
return false;
} else if (passwordValue.length < 8) {
passwordError.textContent = "비밀번호를 8자 이상 입력해 주세요.";
passwordInput.classList.add("error");
return false;
}
passwordError.textContent = ""; // 에러 메시지 초기화
passwordInput.classList.remove("error");
return true;
}

function updateSubmitLoginState() {
const isEmailValid = validateEmail();
const isPasswordValid = validatePassword();
submitBtn.disabled = !(
emailTouched &&
passwordTouched &&
isEmailValid &&
isPasswordValid
);
}

// 폼 제출 시 유효성 검사
form.addEventListener("submit", (event) => {
const isEmailValid = validateEmail();
const isPasswordValid = validatePassword();

if (!isEmailValid || !isPasswordValid) {
event.preventDefault(); // 폼 제출 방지
Copy link
Collaborator

Choose a reason for hiding this comment

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

form 의 method=post 때문에 잘 동작이 안되서 event.preventDefault() 를 하고 /item으로 가도록 작성했는데 이에 문제점이 많을 것 같습니다. 여기에 대한 피드백 부탁드립니다.
-> 문제 될 거 없습니다! 요즘은 오히려 preventDefault를 더 많이 사용합니다. submit 기본 이벤트의 경우 새로고침을 하기 때문에 최근 React, vue 등이 추구하는 SPA에 잘 맞지 않습니다 :) 다만 앞으로 form에서만 뿐만 아니라 preventDefault를 쓰실 때 기본 동작이 어떤 것이고 어떤 것을 막는지 명확하게 찾아보시면 좋겠죠~!

} else {
event.preventDefault(); // 기본 제출 방지
window.location.href = "/items";
}
updateSubmitLoginState();
});

// 입력 필드에서 포커스가 벗어날 때 유효성 검사
emailInput.addEventListener("blur", () => {
emailTouched = true;
validateEmail();
});
passwordInput.addEventListener("blur", () => {
passwordTouched = true;
validatePassword();
});
// 입력 필드에서 값이 변경될 때 버튼 상태 업데이트
emailInput.addEventListener("input", updateSubmitLoginState);
passwordInput.addEventListener("input", updateSubmitLoginState);
});
// 로그인 버튼 클릭 시 로그인 처리
146 changes: 146 additions & 0 deletions sign.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
document.addEventListener("DOMContentLoaded", () => {
const emailInput = document.getElementById("signup-email");
const usernameInput = document.getElementById("signup-username");
const passwordInput = document.getElementById("signup-password");
const passwordConfirmInput = document.getElementById(
"signup-password-confirm"
);
const emailError = document.getElementById("signup-email-error");
const usernameError = document.getElementById("signup-username-error");
const passwordError = document.getElementById("signup-password-error");
const passwordConfirmInputError = document.getElementById(
"signup-password-confirm-error"
);
const form = document.querySelector(".login-form");
const submitBtn = document.querySelector(".btn-large");

submitBtn.disabled = true; // 초기 상태에서 버튼 비활성화

// 필드별로 touched 상태를 추적
let emailTouched = false;
let usernameTouched = false;
let passwordTouched = false;
let passwordConfirmTouched = false;

// 유효성 검사 함수
function validateEmail() {
if (!emailTouched) return true;
const emailValue = emailInput.value.trim();
if (!emailValue) {
emailError.textContent = "이메일을 입력해 주세요.";
emailInput.classList.add("error");
return false;
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(emailValue)) {
emailError.textContent = "잘못된 이메일입니다.";
emailInput.classList.add("error");
return false;
}
emailError.textContent = ""; // 에러 메시지 초기화
emailInput.classList.remove("error");
return true;
}

function vaildateUsername() {
if (!usernameTouched) return true;
const usernameValue = usernameInput.value.trim();
if (!usernameValue) {
usernameError.textContent = "닉네임을 입력해 주세요.";
usernameInput.classList.add("error");
return false;
}
usernameError.textContent = ""; // 에러 메시지 초기화
usernameInput.classList.remove("error");
return true;
}

function validatePassword() {
if (!passwordTouched) return true;
const passwordValue = passwordInput.value.trim();
if (!passwordValue) {
passwordError.textContent = "비밀번호를 입력해 주세요.";
passwordInput.classList.add("error");
return false;
} else if (passwordValue.length < 8) {
passwordError.textContent = "비밀번호를 8자 이상 입력해 주세요.";
passwordInput.classList.add("error");
return false;
}
passwordError.textContent = ""; // 에러 메시지 초기화
passwordInput.classList.remove("error");
return true;
}

function validateConfirmPassword() {
if (!passwordConfirmTouched) return true;
const passwordConfirmValue = passwordConfirmInput.value.trim();
const passwordValue = passwordInput.value.trim();
if (!passwordConfirmValue) {
passwordConfirmInputError.textContent =
"비밀번호를 다시 입력해 주세요.";
passwordConfirmInput.classList.add("error");
return false;
} else if (passwordConfirmValue !== passwordValue) {
passwordConfirmInputError.textContent =
"비밀번호가 일치하지 않습니다.";
passwordConfirmInput.classList.add("error");
return false;
}
passwordConfirmInputError.textContent = ""; // 에러 메시지 초기화
passwordConfirmInput.classList.remove("error");
return true;
}
// 회원가입 상태 업데이트
function updateSubmitSignupState() {
const isEmailVaild = validateEmail();
const isUsernameValid = vaildateUsername();
const isPasswordValid = validatePassword();
const isPasswordConfirmValid = validateConfirmPassword();
submitBtn.disabled = !(
emailTouched &&
usernameTouched &&
passwordTouched &&
passwordConfirmTouched &&
isEmailVaild &&
isUsernameValid &&
isPasswordValid &&
isPasswordConfirmValid
);
}
// 폼 제출 시 유효성 검사
form.addEventListener("submit", (event) => {
const isEmailValid = validateEmail();
const isPasswordValid = validatePassword();

if (!isEmailValid || !isPasswordValid) {
event.preventDefault(); // 폼 제출 방지
} else {
event.preventDefault(); // 폼 제출 방지
window.location.href = "/login.html";
}
updateSubmitLoginState();
});

// 입력 필드에서 포커스가 벗어날 때 유효성 검사
emailInput.addEventListener("blur", () => {
emailTouched = true;
validateEmail();
});
usernameInput.addEventListener("blur", () => {
usernameTouched = true;
vaildateUsername();
});
passwordInput.addEventListener("blur", () => {
passwordTouched = true;
validatePassword();
});
passwordConfirmInput.addEventListener("blur", () => {
passwordConfirmTouched = true;
Copy link
Collaborator

Choose a reason for hiding this comment

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

토글 아이콘 동작까지 만들고 다시 확인해보니 버튼 활성화가 원하는 대로 잘 안되었습니다. 어떤 코드에서 문제가 있는 지 궁금합니다.
-> 버튼 활성화 상태는 input에 달려고, passwordConfirmTouched = true; 이게 blur에 있어서 잘 안됐던 것이 아닐까요~? 🤔 문제를 찾으실 때 차근차근 콘솔로 찍어보시면 좋습니다 :)
버튼 상태가 안바뀌니

submitBtn.disabled = !(
            emailTouched &&
            usernameTouched &&
            passwordTouched &&
            passwordConfirmTouched &&
            isEmailVaild &&
            isUsernameValid &&
            isPasswordValid &&
            isPasswordConfirmValid
        );

이 요소들을 콘솔로 찍고 확인해 보시는거죠~!

Copy link
Collaborator

Choose a reason for hiding this comment

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

+추가로, vscode쓰신다면 https://velog.io/@lgsgst5613/Vscode-Extension-%EC%B6%94%EC%B2%9CTurbo-console-log
이런거 쓰시면 편합니다 🤣

validateConfirmPassword();
});
// 입력 필드에서 값이 변경될 때 버튼 상태 업데이트
emailInput.addEventListener("input", updateSubmitSignupState);
Copy link
Collaborator

Choose a reason for hiding this comment

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

이벤트 버블링을 이용해 form에 달아도 좋습니다~!

usernameInput.addEventListener("input", updateSubmitSignupState);
passwordInput.addEventListener("input", updateSubmitSignupState);
passwordConfirmInput.addEventListener("input", updateSubmitSignupState);
});
// 로그인 버튼 클릭 시 로그인 처리
Loading
Loading