이걸해냄 시리즈는 위코드 실습 과제를 진행하면서 성공/실패 사례를 모아놓은 시리즈입니다.리펙토링이 이루어질 시 수정된 코드가 올라옵니다.
webucks project_220221
이런 걸 만들었습니다.
css는 금방 만들었으므로, 설명을 생략합니다!
<body class="gray-body">
<div class="wrap-login">
<section class="login-section">
<h2 class="hidden">로그인 폼</h2>
<h1 class="webucks-logo big-logo">webucks</h1>
<!--form Start-->
<form class="login-form">
<div class="input-box">
<input id="inputId" type="text" class="input-default" placeholder="전화번호, 사용자 이름 또는 이메일" />
</div>
<div class="input-box">
<input id="inputPw" type="password" class="input-default" placeholder="비밀번호" />
</div>
<button type='button' id="loginBtn" class="btn primary" disabled>로그인</button>
<div class="form-end">
<a class="inline-link" href="$">비밀번호를 잊으셨나요?</a>
</div>
</form>
<!--form End-->
</section>
</div>
<script type="text/javascript" src="js/webucks.js"></script>
</body>
기능 구현에서 실행시켜야 할 기능은 이것들입니다.
- id에 @가 포함되고, password가 8자 이상이 되면 버튼이 활성화 되도록 해주세요.
- 원래 연한 파란색이었다가 → 활성화 되면 밝고 진한 파란색으로
- id, password가 조건에 맞을 때 로그인 버튼을 누르면 list 페이지로 이동해야 합니다.
그런데 저는 그것으로 만족하지 못했습니다. 저 화면의 회색 input
입력창이 보이시나요?
이부분, 텍스트를 입력할 때에도 여전히 회색일텐데 굉장히 기분이 찝찝하지 않나요?
input
창에서 텍스트 입력 시 배경이 흰색이 되며, 텍스트가 하나도 적히지 않을 때에는 다시 회색으로 돌아옴.
이것까지 만들 겁니다.
위의 기능을 구현하기 위해 흐름을 정리하였습니다.
input 동작
- 변수 지정
- id 입력칸이나 pw 입력칸의 값이 0일 경우, 함수 시작
2-1. 여기서 아이디에 @가 들어가고 비밀번호가 8자 이상이면 로그인 버튼 활성화
login button 동작
- 변수 지정
- enter 키를 눌러도 로그인 버튼이 눌리도록 기능 추가
좀더 욕심을 부려 로그인버튼에 2번 기능을 하나 더 추가했습니다.
이때까지는 이걸 금방 만들 줄 알았죠.
let inputBox = document.querySelectorAll('.input-box');//ⓐ
const inputId = document.getElementById('inputId'),//ⓑ
inputPw = document.getElementById('inputPw'),//ⓒ
loginBtn = document.getElementById('loginBtn');//ⓓ
const idLength = inputId.value.length;//id의 값
저는 입력란의 input
을 바깥 div
로 한번 더 감싸주는 짓을 저질렀기 때문에 사실상 배경색이 바뀌어야 하는건 저 ⓐ부분입니다.
//html이 이런 구조다.
<div class="input-box">
<input id="inputId" type="text" class="input-default" placeholder="전화번호, 사용자 이름 또는 이메일" />
</div>
저의 input
은 그냥 공간만 차지하고 투명한 스타일을 가졌어요.
(inputId.value.length > 0) ? inputId.parentNode.style.backgroundColor = '#fff': inputId.parentNode.style.backgroundColor = '#efefef';
loginBtn.disabled = true;
뭔가 요상한 문법이 나왔습니다.
이번에 새로 배운 삼항 조건 연산자라는 것을 써봤습니다.
어쨌든 inputId
의 입력값이 0개가 넘어가있으면, inputId
의 부모 요소인 div
를 찾아 그것의 backgroundColor
를 흰색으로 바꿔주라는 이야기에요. 그리고 loginBtn
은 멋대로 불이 들어오지 못하게 disabled
속성을 유지합니다.
문제가 생겼는데
이렇게 값을 입력한 상태에서 페이지를 새로고침하면, id를 담은 입력란은 저 값을 유지하고 있어요.패스워드 입력칸은 자연스럽게 리셋이 됩니다.
그런데 aaa@mail.com에다가 패스워드를 8자 입력해서 로그인버튼이 활성화 된 채 새로고침을 해도 로그인 버튼에 불이 들어와있더라고요.
해결했어요
새로고침 현상이 있어도 흰색 배경을 유지할 수 있도록 위처럼 명령을 따로 빼줬습니다.
inputBox.forEach((item, index) => {
let inputText = inputBox[index].firstElementChild;
});
일단 두 inputBox
에다가 기능을 먹여줘야 할것 같아서 forEach
를 썼습니다. 사실 저걸 쓰기 싫었는데 for in문이라던가, 그걸로 잘 안 되더라고요. 매개변수에 index
한개만 받고 싶었지만 그러는 순간 index
를 인식하지 못하는 문제가 생겨 어쩔수 없이 필요없는 item
까지 받음.
inputBox.forEach((item, index) => {
let inputText = inputBox[index].firstElementChild;
inputText.addEventListener('keyup', e => {
const changeInputBgColor = () => {
let inputBgColor = e.target.parentNode.style;
//backgroundColor까지 변수로 지정할경우 백그라운드 컬러를 잡아내지 못함
if (!!e.target.value > 0) {
//!!이 없으면 작동하지 않음.
inputBgColor.backgroundColor = "#fff";
//01-3.id 창에 @이 포함되고, 비밀번호가 8자 이상인지 체크
if (inputId.value.includes('@') && inputPw.value.length >= 8) {
loginBtn.disabled = false;
}
} else {
inputBgColor.backgroundColor = '#efefef';
loginBtn.disabled = true;
}
}
changeInputBgColor();
});
});
inputText
에다가 keyup
이벤트가 일어나면 함수를 실행하도록 했습니다. 함수 이름은 changeInputBgColor
에요.
이벤트가 일어난 input
의 부모인 div
의 스타일을 지정합니다. 그런데 이상하게 backgroundColor
속성까지 변수로 지정하면 그걸 못 읽어내어 backgroundColor
는 직접 지정해주기로 했습니다.
input
에 값이 하나라도 입력되는 순간 .input-box
의 배경색은 흰색으로 바뀔거에요.여기서도 사실 if문 대신 삼항조건 연산자를 쓰려 했는데,이렇게 조건이 여러개인 경우는 어떻게 써야할지 몰라서 if문을 썼어요.(물론 시도해봤지만 실패)
문제
if (!!e.target.value > 0) {...}
여기서 앞의 !!
연산자가 없으면 작동하지 않습니다. 왜 그럴까요?
일단 !
이 NOT 연산자고, !!
이렇게 쓰면 값을 불린형으로 변환할 수 있습니다.
하지만 if문의 지정한 조건이 true
인 경우 명령문을 자동으로 실행할텐데요.
해결 못함
- 22.02.25 업데이트
if (e.target.value.length > 0)
값의 글자수라고 지정을 해줘야 했습니다. 이런 실수를...
해결!
이제 나머지는 위의 조건에 맞게, if문으로 아이디에 @이 들어가고 패스워드가 8자 이상이 입력되면 loginBtn
을 활성화시키라는 명령만 넣어줬습니다.
잊어버리지 않고 changeInputBgColor
함수도 호출하기.
일단 제일 간단한 방법은 시맨틱 태그인 <form>
에다가 action
을 추가하여 이동할 페이지를 지정해주는 것입니다.
<form class="login-form" action="coffeelist.html">
<div class="input-box">
<input id="inputId" type="text" class="input-default" placeholder="전화번호, 사용자 이름 또는 이메일" />
</div>
<div class="input-box">
<input id="inputPw" type="password" class="input-default" placeholder="비밀번호" />
</div>
<button type='button' id="loginBtn" class="btn primary" disabled>로그인</button>
<div class="form-end">
<a class="inline-link" href="$">비밀번호를 잊으셨나요?</a>
</div>
</form>
하지만 저는 이렇게 하지 않고 로그인 버튼을 눌렀을때 함수를 실행하는 형식으로 했습니다.
function goUrl() {
let link = 'coffeelist.html';
location.href = link;
}
loginBtn.addEventListener('click', goUrl);
일단 페이지를 이동하는 메소드 자체는 location.href
을 통해 간단히 구현이 가능했습니다.
그런데...
문제
페이지가 자꾸 새로고침되는 현상으로 약 1.5일을 허비한 것 같습니다.
이렇게 해결
<button type='button' id="loginBtn" class="btn primary" disabled>로그인</button>
여기서 버튼 태그에 type='button'
을 추가해주는 이유가 있습니다.
버튼 태그는 기본적으로 type='submit'
속성을 가지고 있기에 타입 지정을 따로 해주지 않으면
form
태그 안에 들어있을때 무한 새로고침을 하게 됩니다.
이 글을 보고 해결했어요
이렇게 해도 됩니다
<!--html-->
<button type='button' id="loginBtn" class="btn primary" onclick="goUrl()" disabled>로그인</button>
이렇게 onclick
속성을 준 후
//loginBtn.addEventListener('click', goUrl);
addEventListener
를 삭제해도 됩니다.
document.onkeyup = function (e) {
let keyCode = e.keyCode;
if (keyCode === 13) goUrl();
}
페이지 내에서 enter
키코드를 가진 keyup
이벤트가 발생하면,이 함수가 실행됩니다.
구현에 큰 문제는 없던 것으로!
이걸 잊어버릴뻔했네요! 간단하게 css로 처리가 가능합니다.
.btn:disabled {
opacity: 0.5;
}
버튼이 비활성화 되면 투명도가 50%로 낮아져, 활성화 시 이런 색이 됩니다.
// 변수 지정
let inputBox = document.querySelectorAll('.input-box');
const inputId = document.getElementById('inputId'),
inputPw = document.getElementById('inputPw'),
loginBtn = document.getElementById('loginBtn');
const idLength = inputId.value.length;
//input text 입력 시 백그라운드 변경, 아이디와 pw 값 체크
(inputId.value.length > 0) ? inputId.parentNode.style.backgroundColor = '#fff': inputId.parentNode.style.backgroundColor = '#efefef';
loginBtn.disabled = true;
inputBox.forEach((item, index) => {
let inputText = inputBox[index].firstElementChild;
inputText.addEventListener('keyup', e => {
const changeInputBgColor = () => {
let inputBgColor = e.target.parentNode.style;
if (e.target.value.length > 0) {
inputBgColor.backgroundColor = "#fff";
if (inputId.value.includes('@') && inputPw.value.length >= 8) {
loginBtn.disabled = false;
}
} else {
inputBgColor.backgroundColor = '#efefef';
loginBtn.disabled = true;
}
}
changeInputBgColor();
});
});
//login btn 작동
function goUrl() {
let link = 'coffeelist.html';
location.href = link;
}
loginBtn.addEventListener('click', goUrl);
document.onkeyup = function (e) {
let keyCode = e.keyCode;
if (keyCode === 13) goUrl();
}
물론 리펙토링은 필요하겠지만..일단은 구현했다는 점에 의의를 두려 합니다!
let inputBgColor1 = e.target.parentNode.style;
let inputBgColor2 = e.target.parentNode.style.backgroundColor;
//backgroundColor까지 변수로 지정할경우 백그라운드 컬러를 잡아내지 못함
console.log(inputBgColor1);
console.log(inputBgColor2);
.
.
.
이렇게 div.input-box
의 backgroundColor
속성을 자바스크립트가 읽어내지 못하는 문제가 있었습니다.이 부분에 대해서 멘토님들께 설명을 들었습니다!
콘솔로그 결과를 본다면,
이렇게 inputBgColor1
는 객체 형태,inputBgColor2
는 문자열 형태로 출력됩니다.
❌안돼요
let inputBgColor2 = e.target.parentNode.style.backgroundColor;
inputBgColor2 = '#000';
즉 이렇게 명령을 내려도, 바뀌는 것은 rgb(255,255,255)
라는 문자열이 #000
으로 변경되는 것일 뿐입니다.
⭕잘돼요
let inputBgColor1 = e.target.parentNode.style;
inputBgColor1.backgroundColor = '#000';
이 경우에는 해당 엘리먼트의 style 객체에서 backgroundColor
의 값을 가져와 해당 색상 코드로 변경하는 것이기 때문에 작동이 되는거였습니다!
🔸 내가 겪은 현상에 대한 stackoverflow 케이스
👩🏫 멘토님 코멘트 : "그런데 애초에
input
을div
로 감쌀 필요가 있었을까요?그러면 색 변경이 더 쉬웠을거에요."
그러게 말이에요..개수도 2개밖에 안되는데, 관리하기도 쉽게 이런 페이지는 바로 input
을 넣어주는게 나을 것 같습니다.